Git відстежує вміст файлів, а не каталоги. Каталог існує в репозиторії лише як tree-об'єкт, і tree створюється тільки тоді, коли в ньому є хоча б один файл. Порожній каталог нічого не додає до дерева - тому git add empty/ нічого не робить, а після клонування його немає.
Як зберегти порожній каталог - покласти в нього файл:
touch storage/logs/.gitkeep
.gitkeep - лише угода, а не особливий файл для Git. Laravel використовує інший прийом - .gitignore всередині каталогу:
# storage/logs/.gitignore
*
!.gitignore
Каталог існує в репозиторії (завдяки цьому файлу), а його вміст ігнорується.
Права файлів - лише кілька режимів. Tree зберігає для кожного запису режим, ім'я і хеш:
git ls-tree HEAD
# 100644 blob 7898192... a.txt ← звичайний файл
# 100755 blob 1a24852... run.sh ← виконуваний файл
# 120000 blob 8d14cbf... link ← символьне посилання
# 040000 tree 3c4e9cd... app ← каталог
# 160000 commit 9f2b1e0... vendor/pkg ← підмодуль (gitlink)
| Режим | Значення |
|---|---|
100644 |
звичайний файл |
100755 |
виконуваний файл |
120000 |
symlink - blob містить шлях, на який він вказує |
040000 |
каталог (tree) |
160000 |
підмодуль - посилання на коміт іншого репозиторію |
Що Git не зберігає: власника, групу, права на запис для групи чи інших, дату зміни. Після клонування файли отримують власника й поточну дату, а права - за umask системи.
Типова проблема - «змінений» файл без змін у вмісті:
old mode 100644
new mode 100755
Хтось виконав chmod +x, або файлова система (Windows, змонтований диск) не підтримує біт виконання. Якщо зміни прав не мають значення для проєкту:
git config core.fileMode false
А щоб справді зробити скрипт виконуваним у репозиторії на системі без підтримки прав - git update-index --chmod=+x deploy.sh.