622

I use Git in Windows, and want to push the executable shell script into git repo by one commit.

Usually I need to do two steps (git commit).

$ vi install.sh
$ git add install.sh  
$ git commit -am "add new file for installation" # first commit
[master f2e92da] add support for install.sh
 1 files changed, 18 insertions(+), 3 deletions(-)
 create mode 100644 install.sh
$ git update-index --chmod=+x install.sh
$ git commit -am "update file permission"        # second commit
[master 317ba0c] update file permission
  0 files changed
  mode change 100644 => 100755 install.sh

How can I combine these two steps into one step? git configuration? windows command?

Reference: see question in Git file permissions on Windows for second commit

phuclv
  • 37,963
  • 15
  • 156
  • 475
Larry Cai
  • 55,923
  • 34
  • 110
  • 156
  • 35
    With git 2.9.x/2.10 (Q3 2016), `git add --chmod=+x` is actually possible. See [my answer below](http://stackoverflow.com/a/38285462/6309), credit to [Edward Thomson](http://stackoverflow.com/users/729881/edward-thomson). – VonC Jul 09 '16 at 19:18
  • 9
    It would be worth updating the selected answer to the `git add --chmod=+x` version – mikemaccana Sep 17 '18 at 10:54

7 Answers7

915

There's no need to do this in two commits, you can add the file and mark it executable in a single commit:

C:\Temp\TestRepo>touch foo.sh

C:\Temp\TestRepo>git add foo.sh

C:\Temp\TestRepo>git ls-files --stage
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0       foo.sh

As you note, after adding, the mode is 0644 (ie, not executable). However, we can mark it as executable before committing:

C:\Temp\TestRepo>git update-index --chmod=+x foo.sh

C:\Temp\TestRepo>git ls-files --stage
100755 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0       foo.sh

And now the file is mode 0755 (executable).

C:\Temp\TestRepo>git commit -m"Executable!"
[master (root-commit) 1f7a57a] Executable!
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100755 foo.sh

And now we have a single commit with a single executable file.

Edward Thomson
  • 74,857
  • 14
  • 158
  • 187
  • 1
    Note that as per https://stackoverflow.com/a/38285462/1852005, since 2016, marking it executable locally through `chmod +x ` will result in the committed file to also be executable. – stwr667 Dec 16 '22 at 05:46
  • 1
    Helpful for commits in WSL. – Weekend Apr 24 '23 at 08:49
291

Indeed, it would be nice if git-add had a --mode flag

git 2.9.x/2.10 (Q3 2016) actually will allow that (thanks to Edward Thomson):

git add --chmod=+x -- afile
git commit -m"Executable!"

That makes the all process quicker, and works even if core.filemode is set to false.

See commit 4e55ed3 (31 May 2016) by Edward Thomson (ethomson).
Helped-by: Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit c8b080a, 06 Jul 2016)

add: add --chmod=+x / --chmod=-x options

The executable bit will not be detected (and therefore will not be set) for paths in a repository with core.filemode set to false, though the users may still wish to add files as executable for compatibility with other users who do have core.filemode functionality.
For example, Windows users adding shell scripts may wish to add them as executable for compatibility with users on non-Windows.

Although this can be done with a plumbing command (git update-index --add --chmod=+x foo), teaching the git-add command allows users to set a file executable with a command that they're already familiar with.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
73

If the files already have the +x flag set, git update-index --chmod=+x does nothing and git thinks there's nothing to commit, even though the flag isn't being saved into the repo.

You must first remove the flag, run the git command, then put the flag back:

chmod -x <file>
git update-index --chmod=+x <file>
chmod +x <file>

then git sees a change and will allow you to commit the change.


Required git config for the committer (credit: Nabi’s answer):

git config core.filemode false

Required git config for the cloner:

git config --global core.autocrlf input
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 3
    ... terrible! is that still the case – MrR May 27 '21 at 22:08
  • @MrR Yes, still the case. I believe this is the fastest way (least git fu) to fix it. – Bohemian May 27 '21 at 22:10
  • I did that, git sees the change, I did commit and push to repo, and when I use the file elsewhere, permission denied...any idea what can be wrong? I download the file from repo and check permissions and it doesnt have executable... – mrRobot Jan 09 '22 at 01:46
  • @mrRobot check `git config`: `core.filemode` should be false. If not, `git config core.filemode false` (credit [Nabi’s answer](https://stackoverflow.com/a/46136322/256196)) – Bohemian Jan 09 '22 at 05:14
  • @Bohemian aw snap, I had `core.filemode` set to `true` and I did what you suggested in your answer above and it was committed to repository WITH +x permission but the problem is that AWS beanstalk clones the repo for its use and it is cloned without +x ...any idea what could be wrong? – mrRobot Jan 09 '22 at 13:28
  • @mrRobot AWS account permissions? Maybe the account doing the clone doesn't have permission to create an executable file in the directory being cloned to (or similar problem)? – Bohemian Jan 09 '22 at 13:39
  • 1
    @Bohemian maybe this helped me: `git config --global core.autocrlf input` – mrRobot Jan 09 '22 at 15:20
28

I have no touch and chmod command in my cmd.exe and git update-index --chmod=+x foo.sh doesn't work for me.

I finally resolve it by setting skip-worktree bit:

git update-index --skip-worktree --chmod=+x foo.sh
khiav reoy
  • 1,373
  • 13
  • 14
  • It's important to note that `update-index --skip-worktree` tells git to **ALWAYS IGNORE** future changes to this file! https://compiledsuccessfully.dev/git-skip-worktree/ – Stefan Zhelyazkov Sep 09 '22 at 20:13
27

The note is firstly you must sure about filemode set to false in config git file, or use this command:

git config core.filemode false

and then you can set 0777 permission with this command:

git update-index --chmod=+x foo.sh
Nabi K.A.Z.
  • 9,887
  • 6
  • 59
  • 81
7

What I had to do to get this working for me was:

  1. To NOT use GitHub Desktop to commit it, it would not recognize the change and so wouldn't commit
  2. Instead, in a terminal, I ran git add --chmod=+x foo.sh
  3. Then git commit -m"Executable!"
Akaisteph7
  • 5,034
  • 2
  • 20
  • 43
0

Based upon the other answers here, you might find these aliases useful to add to your .gitconfig file.

…
[alias]
  …
  stage = add
  stagex = add --chmod=+x
  unstage = restore --staged
  setmodx = update-index --chmod=+x

stagex adds the file with the executable permission bit turned on. setmodx turns on the executable permission for a file already staged or committed. The other aliases are given to show how these two fit in.

Garret Wilson
  • 18,219
  • 30
  • 144
  • 272
  • Technically this is not an answer but "additional useful information to the existing answers", but Stack Overflow doesn't allow multiline code snippets in comments, unfortunately. – Garret Wilson Mar 12 '23 at 15:57