Skip to content

Commit 1a04c15

Browse files
committed
improve index mode for files with executable bit
The fix for #430 in bebc4f5 (Use correct mode for executable files, 2016-05-19) is incomplete. It fails (in most cases) when files have modes which are not exactly 0644 or 0755. Git only cares whether the executable bit is set (or not). Ensure the mode we set for the index is either 100644 or 100755 based on whether the executable bit is set for the file owner. Do this similarly to how upstream git does it in cache.h¹. Add a test covering various file modes to help catch regressions. Fixes #1253 ¹ https://github.com/git/git/blob/v2.31.1/cache.h#L247
1 parent eae0e37 commit 1a04c15

File tree

2 files changed

+15
-3
lines changed

2 files changed

+15
-3
lines changed

git/index/fun.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
S_ISDIR,
1212
S_IFMT,
1313
S_IFREG,
14+
S_IXUSR,
1415
)
1516
import subprocess
1617

@@ -115,7 +116,7 @@ def stat_mode_to_index_mode(mode):
115116
return S_IFLNK
116117
if S_ISDIR(mode) or S_IFMT(mode) == S_IFGITLINK: # submodules
117118
return S_IFGITLINK
118-
return S_IFREG | 0o644 | (mode & 0o111) # blobs with or without executable bit
119+
return S_IFREG | (mode & S_IXUSR and 0o755 or 0o644) # blobs with or without executable bit
119120

120121

121122
def write_cache(entries: Sequence[Union[BaseIndexEntry, 'IndexEntry']], stream: IO[bytes],

test/test_fun.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from io import BytesIO
2-
from stat import S_IFDIR, S_IFREG, S_IFLNK
2+
from stat import S_IFDIR, S_IFREG, S_IFLNK, S_IXUSR
33
from os import stat
44
import os.path as osp
55
from unittest import SkipTest
66

77
from git import Git
88
from git.index import IndexFile
99
from git.index.fun import (
10-
aggressive_tree_merge
10+
aggressive_tree_merge,
11+
stat_mode_to_index_mode,
1112
)
1213
from git.objects.fun import (
1314
traverse_tree_recursive,
@@ -206,6 +207,16 @@ def assert_entries(entries, num_entries, has_conflict=False):
206207
assert_entries(aggressive_tree_merge(odb, trees), 2, True)
207208
# END handle ours, theirs
208209

210+
def test_stat_mode_to_index_mode(self):
211+
modes = (
212+
0o600, 0o611, 0o640, 0o641, 0o644, 0o650, 0o651,
213+
0o700, 0o711, 0o740, 0o744, 0o750, 0o751, 0o755,
214+
)
215+
for mode in modes:
216+
expected_mode = S_IFREG | (mode & S_IXUSR and 0o755 or 0o644)
217+
assert stat_mode_to_index_mode(mode) == expected_mode
218+
# END for each mode
219+
209220
def _assert_tree_entries(self, entries, num_trees):
210221
for entry in entries:
211222
assert len(entry) == num_trees

0 commit comments

Comments
 (0)