Як я можу додати порожній каталог до сховища Git?


4262

Як я можу додати порожній каталог (який не містить файлів) до сховища Git?


16
Хоча це не корисно, є спосіб зламати порожній (справді порожній) каталог у вашу репо . checkoutОднак це не буде з поточними версіями Git.
tiwo

335
@tiwo Я не погоджуюся, що це не корисно. Ієрархія вашого каталогу є частиною вашого проекту, тому його слід контролювати версії.
JBentley

114
У моєму випадку я хотів би додати структуру каталогу для файлів tmp, але не самих файлів tmp. Роблячи це, мій тестер має правильну структуру (інакше трапляються помилки), але я не засмічую свої комісії даними tmp. Так що так, мені це корисно!
Адам Маршалл

45
@AdamMarshall Я думаю, що tiwo говорив, що хак не корисний, оскільки він ігнорується під замовленням. Tmp dirs виглядають як корисна функція для VCS.
Quantum7

31
Чому б не створити процедуру, яка створює файли tmp, також створити каталог tmp?
RyPeck

Відповіді:


4125

Інший спосіб зробити каталог (майже) порожнім (у сховищі) - це створити .gitignoreфайл всередині цього каталогу, який містить ці чотири рядки:

# Ignore everything in this directory
*
# Except this file
!.gitignore

Тоді ви не повинні отримати замовлення прямо так , що ви повинні зробити в M104 ігрових рішень .

Це також дає перевагу в тому, що файли в цьому каталозі не відображатимуться як "незавершені", коли ви отримуєте статус git.

Як зробити коментар @GreenAsJade стійким:

Я думаю, що варто відзначити, що це рішення робить саме те, про що було задано питання, але це, мабуть, не те, що шукали б багато людей, які розглядали це питання. Це рішення гарантує, що каталог залишатиметься порожнім. Там написано: "Я справді ніколи не хочу, щоб файли тут були зареєстровані". На відміну від "У мене немає жодних файлів для реєстрації тут, але мені потрібен каталог, файли можуть надходити пізніше".


25
Я думаю, що рішення README, запропоноване @JohnMee, слід використовувати разом з цим; файл .gitignore надає пояснення того, що ми хочемо не використовувати під контролем версій, тоді як файл README пояснює, яка мета каталогу, які є дуже важливими фрагментами інформації.
pedromanoel

18
@pedromanoel Я пишу документацію, яку ви б помістили READMEвсередину .gitignoreфайлу (як коментарі).
Карлос Кампдеррос

69
знайдіть 1 різницю: 1.) порожню папку, 2.) папку з файлом .gitignore. ;-)
Петро Перхач

6
Це ідеально підходить для папок кеша .
повторний

10
На жаль, це призводить до не порожнього каталогу, в ньому є один прихований файл.
pedorro

1090

Ви не можете. Див. FAQ щодо Git .

Наразі дизайн індексу git (область постановки) дозволяє лише перелічити файли, і ніхто не достатньо компетентний вносити зміни, щоб пусті каталоги не піклувалися про цю ситуацію, щоб виправити її.

Каталоги додаються автоматично, додаючи файли всередині них. Тобто каталоги ніколи не повинні додаватися до сховища та не відслідковуються самостійно.

Ви можете сказати " git add <dir>", і він додасть файли туди.

Якщо вам дійсно потрібен каталог для існування в касах, ви повинні створити в ньому файл. .gitignore добре працює для цієї мети; ви можете залишити його порожнім або заповнити імена файлів, які ви очікуєте відобразити в каталозі.


67
Нижче відповідь набагато краще. Те, що git програмного забезпечення низького рівня не дозволяє, для мене не має значення, як ЯК насправді використовувати Git, коли мені потрібен порожній каталог. Додавання 2-го рядка .gitignore мені здається прийнятним.
Амала

1
Добре, якщо потрібно перенести файли в новий каталог, вони не можуть це зробити, git mvоскільки git поскаржиться, що новий каталог не знаходиться під контролем версій
lulalala

16
Ви можете прочитати " це неможливо, ви не можете і т. Д. " В усьому Інтернеті для цього частого питання. .gitignoreТрюк є найчастішою відповіддю, і задовольняє багато потреб. Однак можна зробити git track справді порожнім каталогом, дивіться мою відповідь
ofavre

2
Хоча чим більше я думаю про це, тим більше здається, що "SHA хеш порожнього рядка", якщо він існує, насправді був би чітко визначеним ідентифікатором для порожнього дерева, якщо тільки неможливо було б визначити, чи є цей об'єкт дерево чи краплина.
Еміль Лундберг

21
Я бачив багато репостів, які використовують порожній файл .gitkeepдля цього.
Сукіма

759

Створіть порожній файл, який називається .gitkeepв каталозі, і додайте його.


58
Я додав відповідь, що заохочує створити .keepзамість цього.
Акумен

205
.gitkeepGit не був прописаний Git і збирається змусити людей вдруге здогадуватися про його значення, що призведе їх до пошуку Google, що призведе їх сюди. .gitПрефікс конвенція повинна бути зарезервована для файлів і каталогів , які сам Git використовує.
t-март

10
@ t-mart " .gitКонвенція префікса повинна бути зарезервована ..." Чому? Чи git запитує це бронювання?
Обмежене спокутування

9
У цьому випадку a READMEабо ABOUTфайл буде таким же хорошим чи кращим. Залишаючи записку для наступного хлопця, як і ми раніше це робили перед URL-адресами.
Дейв

5
Не працює, якщо ви пишете одиничний тест, який повинен перевірити код у порожньому каталозі ...
thebjorn

436

Ви завжди можете помістити файл README у каталог із поясненням того, чому ви хочете цей, інакше порожній, каталог у сховищі.


39
+1, гарна пропозиція, порожній каталог не має сенсу, якщо він не буде використаний у майбутньому. Тож створіть у ньому файл README і напишіть, для чого цей каталог, і які файли будуть розміщені там у майбутньому. Це вирішує обидві проблеми.
saeedgnu

63
@ilius Дурниця. Структура каталогів, що містить порожні каталоги, може бути дуже бажаною у багатьох ситуаціях (наприклад, програма MVC, де ви хочете довідати каталог моделей, але ще не доводиться створювати жодні моделі, або каталог спільних представлень, до яких ви плануєте пізніше додавати спільні перегляди ). Більше того, розміщення README у кожному з них є надмірним, оскільки очевидно, для чого вони там є, і легко забути поставити README у кожну з них. І вам потрібно пам’ятати, щоб видалити README, коли ви додаєте до них деякі інші файли. В основному, git безумовно повинен дозволяти порожні каталоги.
Їжак

20
@Jez: Я не згоден. Справа в тому, що git призначений для управління (та індексування) вихідного коду. Важливо, що ідентифікатор коміту - це хеш вмісту. Тобто він повинен мати зміст. Вам не потрібно README у кожній частині дерева, лише вузлики листя. Якщо у вас є місця, які ви збираєтесь ввести код, але немає коду, і ви навіть не знайдете часу, щоб повторити "місце для моделей" >> README, то у вас є ідея, а не зобов'язання. Це не цікавить git. Скажіть: "Я хочу, щоб у запущеної програми були порожні каталоги XYZ" - це проблема виконання , а не проблема джерела. Поводьтеся з інсталятором.
Джо Атцбергер

6
@JoeAtzberger Це відсутність функції, а не навмисне обмеження. Із FAQ про Git: Наразі дизайн індексу Git (область постановки) дозволяє лише перелічити файли, і ніхто не достатньо компетентний вносити зміни, щоб пусті каталоги не піклувалися про цю ситуацію, щоб її виправити.
jbo5112

7
@ jbo5112 Так, "спеціальний код", на який ви посилаєтесь, це "інсталятор", про який я згадував. Ваша установка webapp вже має обробляти створення бази даних, локального конфігурації, витягування залежностей або 100 інших операцій, але пара порожніх каталогів знаходиться поза ним? Спробуйте gradle, пасажир, шеф-кухар, примітивний Makefile тощо. Немає різниці в безпеці між створенням каталогів та іншою (потенційно набагато складнішою / небезпечною) роботою встановлення програми. І якщо у вас дійсно немає деп, конфігурації, БД і т.д., а також інсталятора, просто використовуйте README. Жоден випадок не вимагає від вас обох.
Джо Атцбергер

348
touch .keep

У Linux це створює порожній файл з назвою .keep. Оскільки це вартує, це ім’я є агностиком для Git, тоді як .gitkeepбуде специфічним для Git. По-друге, як зазначив інший користувач,.git умовні префікса повинні бути зарезервовані для файлів і каталогів, якими користується сам Git.

Як варіант, як зазначено в іншій відповіді , каталог може містити описовий READMEабо README.mdфайл .

Звичайно, це вимагає, щоб наявність файлу не призвело до розбиття вашої програми.


1
Це добре для початкового голого каталогу, але що робити, якщо він починає заповнюватися файлами? Тоді Git помітить їх і стверджуватиме їх як незатребувані файли. Вибрана відповідь тут працює набагато елегантніше, що дозволяє зберігати каталог, але потім безпечно ігнорувати вміст.
JakeGould

14
Питання та переважне загальне занепокоєння стосується додавання порожнього каталогу. Якщо пізніше він має резидентний файл, очевидно видаліть .keepфайл або просто проігноруйте його. Якщо ж замість цього файли в каталозі слід ігнорувати, то це зовсім інше питання.
Acumenus

3
Було запропоновано git clean -nd | sed s/'^Would remove '// | xargs -I{} touch "{}.keep"зробити це у всіх незавершених порожніх каталогах.
Акумен

1
Це рішення вам не подобається, важко здогадатися, що робить цей файл. Крім того, якщо ви генеруєте файли у вашому середовищі розробників (наприклад, журнали чи зображення тощо), це не запобігає переробці цих файлів та проробленню їх у виробництво, що не приємно.
danielrvt

1
Windows не любить файли без імен, і для цього потрібна спеціальна магія (він же баш-термінальний додаток або його аналог).
EntangledLoops

303

Навіщо нам потрібні порожні папки з версією

Насамперед:

Порожній каталог не може бути частиною дерева в системі версій Git .

Це просто не буде відстежено. Але є сценарії, в яких "версія" порожніх каталогів може мати значення, наприклад:

  • складання заздалегідь заданої структури папок , надання її доступній кожному користувачеві / учаснику сховища; або, як спеціалізований випадок із вищезазначеного, створення папки для тимчасових файлів , таких як cache/або logs/каталоги, де ми хочемо надати папку, але.gitignore її вміст
  • у зв'язку з вищезазначеним, деякі проекти не працюватимуть без папок (що часто натякає на погано розроблений проект, але це частий сценарій у реальному світі, і, можливо, можуть виникнути проблеми, пов'язані з дозволом).

Деякі запропоновані шляхи вирішення

Багато користувачів пропонують:

  1. Розміщення READMEфайлу чи іншого файлу з деяким вмістом для того, щоб зробити каталог не порожнім, або
  2. Створення .gitignoreфайлу з якоюсь "зворотною логікою" (тобто для включення всіх файлів), яка, врешті-решт, служить тій самій цілі підходу №1.

Хоча обидва рішення безумовно працюють, я вважаю їх невідповідними змістовному підходу до версії Git.

  • Чому ви повинні розміщувати фальшиві файли чи README, які, можливо, вам не дуже потрібні у вашому проекті?
  • Навіщо використовувати .gitignoreдля того, щоб робити щось ( зберігання файлів), що є абсолютно протилежним тому, що воно призначене ( за винятком файлів), навіть якщо це можливо?

.Gitkeep підхід

Використовуйте порожній файл під назвою.gitkeep для того, щоб примусити присутність папки в системі версій.

Хоча це може здатися не такою великою різницею:

  • Ви використовуєте файл, який має сингл мету зберігати папку. Ви не поміщаєте туди жодної інформації, яку не хочете вносити.

    Наприклад, ви повинні використовувати README як, ну і README з корисною інформацією, а не як привід для збереження папки.

    Розділення проблем - це завжди добре, і ви можете додати додаток, .gitignoreщоб ігнорувати непотрібні файли.

  • Як називати це, .gitkeepце ясно і зрозуміло з самого імені файлу (а також інших розробників , що добре для спільного проекту та однієї з основних цілей репозиторію Git), що цей файл

    • Файл, не пов'язаний з кодом (через провідну крапку та ім'я)
    • Файл, чітко пов'язаний з Git
    • Її мета ( зберігати ) чітко викладена і послідовна і семантично протилежна за своїм значенням ігнорувати

Усиновлення

Я бачив .gitkeepпідхід, прийнятий в таких важливих рамках, як Laravel , Angular-CLI .


8
Ви пропустили одну думку - в чому причина зберігання та порожньої папки (наприклад, / logs, / tmp, / uploads)? Так - його, щоб папка була порожньою. :) Отже, якщо ви хочете залишати папку порожньою, ви повинні ігнорувати файли всередині неї.
Роман

14
@RomanAllenstein: не обов’язково. Можливо, ви створюєте РЕПО із заданою структурою, яка може бути заповнена пізніше. Ці файли будуть додані до репо, як тільки вони будуть створені, і буде прикро починати видалення чи редагування файлів .gitignore (і небезпечно, тому що, ймовірно, ви навіть не усвідомлюєте, що їх не відстежують: git ігнорує їх )
синійFast

45
@ Beenam: Я візьму підсумки, але моє дослідження мета метаболізму не викликає занепокоєння щодо багатослівних відповідей, якщо вони забезпечують достатню деталізацію та чіткість, щоб бути корисними для кожного читача (і кожного рівня навичок). Я все ще дуже відкритий до будь-якої критики і дякую за те, що цю причину оголосив публічно, я сприймаю це дуже позитивно.
Креніо

4
Якщо ви редагуєте свою відповідь, щоб замінити .gitkeepбудь-яке інше ім'я файлу без префіксації git, ви отримаєте мою нагоду, я вважаю, що ця відповідь є найкращою та найбільш інформативною. Причина: Я думаю, що ".git *" повинен бути зарезервований для файлів, призначених для git, хоча це лише простий заповнювач. Перший мій здогад, коли я побачив, що, наприклад, файл ".gitkeep" буде автоматично ігнорований (це було б приємною особливістю), але це не так, правда?
Джонні

5
Мені цікаво, чому людям так важко зрозуміти, чому потрібно додати "порожні" папки до git. Треба десь починати, правда? Отже, зазвичай ви починаєте зі структури папок своїх проектів і - на жаль, на початку проекту ще нічого немає. Після того, як ваше проектне репо буде виконано, працівники команди можуть клонуватися та почати працювати над структурою SAME.
BitTickler

127

Як описано в інших відповідях, Git не в змозі представляти порожні каталоги в області постановки. (Див. FAQ щодо Git .) Однак, якщо для ваших цілей каталог достатньо порожній, якщо він містить лише .gitignoreфайл, то ви можете створювати .gitignoreфайли в порожніх каталогах лише за допомогою:

find . -type d -empty -exec touch {}/.gitignore \;

21
Можливо, ви захочете ігнорувати каталог .git: find . -name .git -prune -o -type d -empty -exec touch {}/.gitignore \;
steffen

3
Більш простий варіант для більшості ситуаційfind * -type d -empty -exec touch {}/.gitignore \;
акхан

2
Оскільки OS X створює .DS_Store файл майже в кожній дирекції, це не працює. Єдиним (НЕБЕЗПЕЧНИМ!) Способом, який я знайшов, було спочатку видалити всі .DS_Store файли, find . -name .DS_Store -exec rm {} \;а потім використати бажаний варіант з цієї відповіді. Не забудьте виконати це лише у правильній папці!
zerweck

1
Хтось знає спосіб зробити це в Windows з командного рядка? Я бачив деякі рішення тут, в Ruby і Python, але мені б хотілося рішення для баребонів, якщо ним можна керувати.
Mig82

1
@akhan Додавання чогось .gitignoreне впливає на -emptyпрапор findкоманди. Мій коментар стосується видалення .DS_Storeфайлів у дереві директорій, тому -emptyпрапор можна застосувати.
zerweck

68

Енді Лестер правий, але якщо ваш каталог просто повинен бути порожнім, а не порожнім порожнім, ви можете помістити порожній .gitignoreфайл туди як вирішення.

З іншого боку, це проблема впровадження, а не принципова проблема дизайну пам’яті Git. Як вже не раз згадувалося у списку розсилки Git, причиною того, що це не було здійснено, є те, що ніхто не піклується про те, щоб подати патч на нього, а не в тому, що цього не можна чи не слід робити.


4
Саме це я і сказав. Обидва абзаци розглядаються у фрагменті FAQ, який я розмістив.
Енді Лестер

1
Я вважаю, що вбік є нецікавим і корисно знати - це можна виправити, просто не сподівайтеся, що незабаром, коли в більшості випадків буде таке легке вирішення.
wnoise

Вибачте, я не прочитав останній абзац, і, хоча я читав перший абзац, ну, я не впевнений, чому я повторив цю інформацію.
Арістотель Пагалцзіс

2
Звичайно, ця додаткова відповідь служить для вказування на факт.
Майкл Джонсон

Я потрапив сюди, розглядаючи випадок, коли збірка впала, якщо каталог не існує, і за замовчуванням він порожній, але він не повинен бути порожнім. Створення .gitignore робить правильно.
Джошуа

33

Спосіб створення папки журналу Ruby on Rails :

mkdir log && touch log/.gitkeep && git add log/.gitkeep

Тепер каталог журналів буде включено до дерева. Це дуже корисно під час розгортання, тому вам не доведеться писати процедуру для створення каталогів журналів.

Журнали можна зберігати, видаючи,

echo log/dev.log >> .gitignore

але ви, мабуть, це знали.


23
Що це стосується Ruby on Rails?
питання Quolonel


30

Git не відстежує порожні каталоги. Докладніші пояснення див. У FAQ щодо Git . Запропонований спосіб вирішення полягає в тому, щоб помістити .gitignoreфайл у порожній каталог. Мені не подобається таке рішення, тому що.gitignore це "приховано" конвенцією Unix. Також немає пояснень, чому каталоги порожні.

Я пропоную помістити файл README у порожній каталог, пояснюючи, чому каталог порожній та чому його потрібно відслідковувати в Git. Якщо файл README на місці, що стосується Git, каталог більше не порожній.

Справжнє питання - навіщо вам потрібен порожній каталог в git? Зазвичай у вас є якийсь сценарій збірки, який може створити порожній каталог перед компілюванням / запуском. Якщо ні, то зробіть його. Це набагато краще рішення, ніж розміщення порожніх каталогів в git.

Отже, у вас є деякі причини, чому вам потрібен порожній каталог в git. Поставте цю причину у файлі README. Таким чином, інші розробники (і майбутні ви) знаєте, чому порожній каталог повинен бути там. Ви також будете знати, що ви можете видалити порожній каталог, коли проблема, яка потребує порожнього каталогу, вирішена.


Для переліку кожного порожнього каталогу використовуйте таку команду:

find -name .git -prune -o -type d -empty -print

Щоб створити README-заповнювачі заповнення у кожному порожньому каталозі:

find -name .git -prune -o -type d -empty -exec sh -c \
  "echo this directory needs to be empty because reasons > {}/README.emptydir" \;

Щоб ігнорувати все в каталозі, крім файлу README, введіть у ваш ряд наступні рядки .gitignore:

path/to/emptydir/*
!path/to/emptydir/README.emptydir
path/to/otheremptydir/*
!path/to/otheremptydir/README.emptydir

Крім того, ви можете просто виключити ігнорування кожного файлу README:

path/to/emptydir/*
path/to/otheremptydir/*
!README.emptydir

Щоб переглянути список README після їх створення:

find -name README.emptydir

28

ПОПЕРЕДЖЕННЯ: Ця настройка не справді працює, як виявляється. Вибачте за незручності.

Оригінальна публікація нижче:

Я знайшов рішення під час гри з внутрішніми Git!

  1. Припустимо, ви знаходитесь у вашому сховищі.
  2. Створіть порожній каталог:

    $ mkdir path/to/empty-folder
    
  3. Додайте його до індексу за допомогою команди сантехніки та порожнього дерева SHA-1 :

    $ git update-index --index-info
    040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904    path/to/empty-folder
    

    Введіть команду та введіть другий рядок. Натисніть, Enterа потім Ctrl+, Dщоб припинити введення даних. Примітка: формат у режимі [SPACE] введіть шлях [SPACE] SHA-1hash [TAB] (вкладка важлива, форматування відповіді не зберігає її).

  4. Це воно! Ваша порожня папка знаходиться у вашому індексі. Все, що вам потрібно зробити - це скористатися.

Це рішення коротке і, мабуть, працює чудово ( див. РЕДАКЦІЯ! ), Але це не так просто запам'ятати ...

Порожнє дерево SHA-1 можна знайти, створивши нове порожнє сховище Git, cd і видавши git write-tree, яке виводить порожнє дерево SHA-1.

Редагувати:

Я використовую це рішення з тих пір, як знайшов його. Схоже, це працює точно так само, як і створення підмодуля, за винятком того, що ніде не визначений модуль. Це призводить до помилок при видачі git submodule init|update. Проблема полягає в тому, що git update-indexпереписується 040000 treeчастина160000 commit .

Більше того, будь-який файл, розміщений під цим контуром, ніколи не помітить Git, оскільки він вважає, що вони належать до іншого сховища. Це противно, оскільки його легко можна не помітити!

Однак якщо ви ще не (і не будете) використовувати будь-які підмодулі Git у вашому сховищі, і папка "порожня" залишиться порожньою або якщо ви хочете, щоб Git знав про її існування та ігнорував її вміст, ви можете перейти з цей твіст. Йти звичайним способом з підмодулями вживає більше кроків, які це підлаштовує.


Помістивши порожню папку в індекс і зробивши її, чи можливо тоді git svn dcommitїй отримати бажаний результат?
Обмежене спокутування

2
Навряд чи ця настройка буде працювати з будь-яким іншим інструментом. Як зазначено в попередженні та редагуванні, я перешкоджаю його використанню, якщо тільки у досить обмеженому випадку.
ofavre

1
І звичайно, саме тому возитися з внутрішніми органами кишки протипоказано.
Кейсі

@abhisekp Як це можливо?
PyRulez

1
@PyRulez добре, що в світі програмного забезпечення нічого неможливого. : D Насправді я пішов за відповіддю.
abhisekp

21

Скажімо, вам потрібен порожній каталог з назвою tmp :

$ mkdir tmp
$ touch tmp/.gitignore
$ git add tmp
$ echo '*' > tmp/.gitignore
$ git commit -m 'Empty directory' tmp

Іншими словами, вам потрібно додати файл .gitignore до індексу, перш ніж ви зможете сказати Git ігнорувати його (та все інше у порожньому каталозі).


11
Дві речі: Ви можете просто "відлучити" * '> tmp / .gitignore "замість торкання, а" git commit -m "не вносить зміни, зроблені після додавання файлів до індексу.
Крістофер Хаммарстрем

6
Якщо ви просто зробите, echo bla > fileви не отримаєте, file: File existsтому що >буде перезаписаний файл, якщо він вже є, або створити новий, якщо його не існує.
psyrendust

3
/bin/shкультурне припущення! * Якщо "тут" cshі змінна noclobberвстановлена, ви дійсно отримаєте file: File exists. Якщо хтось скаже "Я це розумію", не вважайте, що вони ідіот, і відповідь "Ні, ти цього не робиш". * c2.com/cgi/wiki?AmericanCulturalAssumption
clacke

1
@clacke Якщо хтось вирішить скористатися іншою оболонкою, ніж усі інші, він повинен це прямо заявити, якщо у них виникають проблеми. На відміну від національності, у кожного є вільний вибір оболонки.
SeldomNeedy

2
@SeldomNeedy Можливо, вони шукають допомоги, бо навіть не знають, що використовують іншу оболонку, ніж усі.
clacke

20

Можливо, додавання порожнього каталогу здається, що це був би шлях найменшого опору, оскільки у вас є сценарії, які очікують існування цього каталогу (можливо, тому, що він є ціллю для створених бінарних файлів). Іншим підходом буде модифікація сценаріїв для створення каталогу за потребою .

mkdir --parents .generated/bin ## create a folder for storing generated binaries
mv myprogram1 myprogram2 .generated/bin ## populate the directory as needed

У цьому прикладі ви можете перевірити (порушене) символічне посилання на каталог, щоб мати доступ до нього без префіксу ".generated" (але це необов'язково).

ln -sf .generated/bin bin
git add bin

Коли ви хочете очистити своє початкове дерево, ви можете просто:

rm -rf .generated ## this should be in a "clean" script or in a makefile

Якщо ви використовуєте часто запропонований підхід до перевірки у майже порожній папці, у вас є незначна складність видалення вмісту, не видаляючи також файл .gitignore.

Ви можете проігнорувати всі створені файли, додавши до кореня .gitignore:

.generated

1
Примітка: Символічне посилання, яке я запропонував, "розбивається" при чистому оформленні замовлення, оскільки .generatedкаталог спочатку не існує. Він більше не буде зламаний, як тільки ви зробите свою збірку.
nobar

2
Я погоджуюсь, що в деяких випадках це дуже гарна ідея, але в інших (наприклад, розповсюдження проекту, де у вас є інакше порожній скелет із папками, такими як моделі / та перегляди /), ви хочете, щоб користувач мав ці каталоги під рукою. ніж вручну потрібно читати читати документи, і можна було б трохи очікувати, що вони після запуску репо будуть виконати якийсь інсталяційний сценарій. Я думаю, що ця відповідь у поєднанні з відповіддю README @ john-mee має охоплювати більшість, якщо не всі випадки.
moopet

14

Я зіткнувся з проблемою і з порожніми каталогами. Проблема з використанням файлів заповнювачів полягає в тому, що вам потрібно створити їх і видалити, якщо вони більше не потрібні (адже пізніше були додані підкаталоги або файли. З великими деревами-джерелами, керування цими файлами-заповниками може бути громіздкою і помилкою схильний.

Ось чому я вирішив написати інструмент з відкритим кодом, який може керувати створенням / видаленням таких файлів-заповнювачів автоматично. Він написаний для платформи .NET і працює під Mono (.NET для Linux) та Windows.

Просто подивіться на сторінку: http://code.google.com/p/markemptydirs


14

Мені подобаються відповіді від @ Artur79 та @mjs, тому я використовував комбінацію обох і зробив це стандартом для наших проектів.

find . -type d -empty -exec touch {}/.gitkeep \;

Однак на Mac чи Linux працює лише декілька наших розробників. Дуже багато роботи в Windows, і я не зміг знайти еквівалентного простого однолінійного інструмента, щоб досягти того самого. Деяким пощастило встановити Cygwin з інших причин, але прописати Cygwin саме для цього здавалося непосильним.

Редагуйте для кращого рішення

Отже, оскільки у більшості наших розробників вже встановлено Ant , перше, що я подумав, - це зібрати файл збірки Ant, щоб досягти цього незалежно від платформи. Це ще можна знайти тут

Однак , пізніше я думав , що було б краще зробити це в невелику команду утиліти, так що я відтворив його з допомогою Python і опублікував його в PyPI тут . Ви можете встановити його, просто запустивши:

pip3 install gitkeep2

Це дозволить створювати та видаляти .gitkeepфайли рекурсивно, а також дозволить додавати до них повідомлення для своїх однолітків, щоб зрозуміти, чому ці каталоги важливі. Цей останній шматочок є бонусом. Я подумав, що було б непогано, якби .gitkeepфайли могли самостійно документувати.

$ gitkeep --help
Usage: gitkeep [OPTIONS] PATH

  Add a .gitkeep file to a directory in order to push them into a Git repo
  even if they're empty.

  Read more about why this is necessary at: https://git.wiki.kernel.org/inde
  x.php/Git_FAQ#Can_I_add_empty_directories.3F

Options:
  -r, --recursive     Add or remove the .gitkeep files recursively for all
                      sub-directories in the specified path.
  -l, --let-go        Remove the .gitkeep files from the specified path.
  -e, --empty         Create empty .gitkeep files. This will ignore any
                      message provided
  -m, --message TEXT  A message to be included in the .gitkeep file, ideally
                      used to explain why it's important to push the specified
                      directory to source control even if it's empty.
  -v, --verbose       Print out everything.
  --help              Show this message and exit.

Сподіваюсь, вам це стане в нагоді.


13

Ти не можеш і, на жаль, ніколи цього не зможеш. Це рішення, яке прийняв сам Лінус Торвальд. Він знає, що добре для нас.

Там десь я прочитав, де я читав.

Я знайшов Re: Порожні каталоги .. , але, можливо, є ще один.

Вам доведеться жити з обхідними шляхами ... на жаль.


1
Я знаю, що ви розмістили це як приклад поганого аргументу, але я ціную посилання, тому що це насправді добре аргументований аргумент проти відстеження каталогів. ;-)
clacke

1
Ця відповідь здається непослідовною, оскільки в наступному дописі на посилається потік Лінус Торвальд каже, що очікує, що їм потрібно буде додати відстеження каталогів: markmail.org/message/libip4vpvvxhyqbl . Насправді він каже, що «вітає патчі, які [додають підтримку для відстеження порожніх каталогів» »
Патрік М

Патріку, він також там вживає слово "ідіотський". Я підозрюю, що його формулювання стосується людей тут у цій темі, і тому я припускаю, що він не втілить щось «ідіотське» в Git сам.
користувач2334883

10

Коли ви додаєте .gitignoreфайл, якщо ви збираєтеся помістити в нього будь-яку кількість вмісту (який ви хочете, щоб Git ігнорував), ви можете додати один рядок із простою зірочкою, *щоб переконатися, що ви не додали проігнорований вміст випадково .


9

Немає можливості змусити Git відслідковувати каталоги, тому єдине рішення - додати файл-заповнювач до каталогу, який потрібно відстежувати Git.

Файл може бути названий і містити все, що завгодно, але більшість людей використовують порожній файл з ім'ям .gitkeep(хоча деякі люди вважають за краще VCS-агностик.keep ).

Префікс . позначає його як прихований файл.

Іншою ідеєю було б додати READMEфайл, що пояснює, для чого буде використовуватися каталог.


8

Як уже згадувалося, не можна додавати порожні каталоги, але ось один вкладиш, який додає порожні файли .gitignore у всі каталоги.

ruby -e 'require "fileutils" ; Dir.glob(["target_directory","target_directory/**"]).each { |f| FileUtils.touch(File.join(f, ".gitignore")) if File.directory?(f) }'

Я встромив це в Rakefile для легкого доступу.


6
Я вважаю за краще використовуватиfind . -type d -empty -print0 | xargs --null bash -c 'for a; do { echo "*"; echo "!.gitignore"; } >>"$a/.gitignore"; done' --
Тіно

8

Рішення Джеймі Флоруного чудово працює. Ось трохи покращена версія для збереження .htaccess:

# Ignore everything in this directory
*
# Except this file
!.gitignore
!.htaccess

За допомогою цього рішення ви можете ввести порожню папку, наприклад /log , /tmpабо /cacheі папка буде залишатися порожньою.


2
Він хоче зберігати порожній каталог, а не файл.
gvsrepins

2
І я вже згадував, що це також збереже .htaccess. Приклад: якщо в програмному забезпеченні є каталог для файлів журналів (наприклад, оксид eshop), який не повинен бути доступний через Інтернет, в каталозі є .htaccess. Якщо ви помістите вищезгадане .gitignore у папку, .htaccess не буде коментуватися, і папка буде доступна через Інтернет.
Роман

Якщо у вас є .htaccess файл, який знаходиться під контролем версій, тоді у вас вже є каталог, що містить його під контролем версій. Таким чином, проблема вже вирішена - файл .gitignore стає неактуальним.
Ponkadoodle

1
@Wallacoloo Пов'язане з вашим правильним питанням, але файл корисний, я буду використовувати його для каталогу завантаження, наприклад, у тому випадку, коли файли повинні бути захищені .htaccess. На відміну від пояснення римлян, .htaccess-файл буде вчинено, оскільки він виключений правилом ігнорування. [стара тема, я знаю]
Девід

7

Я завжди будую функцію, щоб перевірити потрібну структуру папок і побудувати її для мене в рамках проекту. Це усуває цю проблему, оскільки порожні папки зберігаються в Git за допомогою проксі.

function check_page_custom_folder_structure () {
    if (!is_dir(TEMPLATEPATH."/page-customs"))
        mkdir(TEMPLATEPATH."/page-customs");    
    if (!is_dir(TEMPLATEPATH."/page-customs/css"))
        mkdir(TEMPLATEPATH."/page-customs/css");
    if (!is_dir(TEMPLATEPATH."/page-customs/js"))
        mkdir(TEMPLATEPATH."/page-customs/js");
}

Це в PHP, але я впевнений, що більшість мов підтримують однаковий функціонал, і тому що про створення папок піклується додаток, папки завжди будуть там.


2
Просто так ми всі на одній сторінці, я цього більше не роблю. Це марна трата часу. .gitkeepКонвенція є набагато кращою практикою.
Легкий фуз

Я не бачу, як це може бути марною тратою часу. Коли ваш TEMPLATEPATH очевидно динамічний, ви не можете використовувати рішення .gitkeep. І навіть при нединамічній структурі папок вам слід додати ще деякі речі замість видалення дуже хорошого рішення перевірки каталогів, наприклад, перевірити наявність дозволів та chmod файлів. Додавання способу позначення каталогів всередині глобального .gitignore було б для мене ідеальним. Щось на кшталт #keep / path / to / dir
Jochen Schultz

7

Ось хак, але смішно, що це працює (Git 2.2.1). Схожий на те, що запропонував @Teka, але простіше запам'ятати:

  • Додайте підмодуль до будь-якого сховища (git submodule add path_to_repo )
  • Це додасть папку та файл .submodules . Внесіть зміни.
  • Видаліть .submodulesфайл і введіть зміни.

Тепер у вас є каталог, який створюється, коли фіксація перевіряється. Цікава річ, що якщо ви подивитеся на вміст дерева-об’єкта цього файлу, ви отримаєте:

fatal: Неправильне ім'я об'єкта b64338b90b4209263b50244d18278c0999867193

Я б не рекомендував використовувати його, хоча він може припинити роботу в майбутніх версіях Git. Що може призвести до пошкодження вашого сховища.


Це насправді спрацьовує, але я думаю, що це бентежить чорт у IntelliJ ...: |
rogerdpack

Я створив краще рішення , засноване на це , що не має цих недоліків: stackoverflow.com/a/58543445/277882
ntninja

7

Багато хто вже відповів на це питання. Просто додайте сюди версію PowerShell.

Знайдіть усі порожні папки в каталозі

Додати туди порожній файл .gitkeep

Get-ChildItem 'Path to your Folder' -Recurse -Directory | Where-Object {[System.IO.Directory]::GetFileSystemEntries($_.FullName).Count -eq 0} | ForEach-Object { New-Item ($_.FullName + "\.gitkeep") -ItemType file}

Nice.‌‌ ༼ ͡☉ ͜ʖ ͡☉ ༽
FiringSquadWitness

6

Якщо ви хочете додати папку, яка буде містити багато перехідних даних у кількох семантичних каталогах, тоді один підхід - додати щось подібне до вашого кореневого .gitignore ...

/app/data/**/*.* !/app/data/**/*.md

Тоді ви можете зафіксувати описові файли README.md (або порожні файли, неважливо, якщо ви можете орієнтуватися на них однозначно, як *.mdу цьому випадку) у кожному каталозі, щоб гарантувати, що всі каталоги залишаються частиною репо, а не Файли (із розширеннями) залишаються ігнорованими. ОБМЕЖЕННЯ:. s заборонено в іменах каталогу!

Ви можете заповнити всі ці каталоги файлами xml / images або будь-яким іншим і додати більше каталогів під /app/data/ протягом часу, коли розвиваються потреби в пам’яті для вашої програми (з файлами README.md, що служать для запису опису того, для чого призначений кожен каталог зберігання точно).

Не потрібно більше змінювати .gitignoreабо децентралізувати, створюючи нову .gitignoreдля кожного нового каталогу. Напевно, це не найрозумніше рішення, але це дуже стильний gitignore-мудрий і завжди працює для мене. Приємно і просто! ;)

введіть тут опис зображення


6

Простий спосіб зробити це - додавши .gitkeepфайл у каталог, який ви хочете (наразі) зберігати порожнім.

Дивіться цю відповідь SOF для отримання додаткової інформації - яка також пояснює, чому деякі люди вважають конкуруючу конвенцію про додавання файлу .gitignore (як зазначено у багатьох відповідях тут) заплутаною.


4

Додавання ще однієї опції до перемоги.

Якщо припустити, що ви хочете додати до нього каталог, gitякий для всіх цілей, пов’язаних із цим git, повинен залишатися порожнім і ніколи не буде відслідковувати його вміст, .gitignoreяк це запропоновано багато разів тут, зробить свою справу.

Формат, як згадувалося, такий:

*
!.gitignore

Тепер, якщо ви хочете, як це зробити в командному рядку, одним махом, тоді як всередині каталогу, який ви хочете додати, ви можете виконати:

$ echo "*" > .gitignore && echo '!.gitignore' >> .gitignore && git add .gitignore

У мене є сценарій оболонки, який я використовую для цього. Назвіть сценарій все, що вам заманеться, або додайте його десь у ваш шлях включення, або посилайтеся на нього безпосередньо:

#!/bin/bash

dir=''

if [ "$1" != "" ]; then
    dir="$1/"
fi

echo "*" > $dir.gitignore && \
echo '!.gitignore' >> $dir.gitignore && \
git add $dir.gitignore

За допомогою цього ви можете виконати його з каталогу, який ви хочете додати, або посилатися на каталог, як на перший і єдиний параметр:

$ ignore_dir ./some/directory

Ще один варіант (у відповідь на коментар @GreenAsJade), якщо ви хочете відстежувати порожню папку, яка МОЖЕ містити відслідковувані файли в майбутньому, але поки що вона буде порожньою, ви можете опустити файл *з цього .gitignoreфайлу і перевірити це . В основному, весь файл говорить: "не ігноруй мене ", але в іншому випадку каталог порожній і відслідковується.

Ваш .gitignoreфайл виглядатиме так:

!.gitignore

Це все, перевірте це, і у вас є порожній, але відслідкований каталог, в який ви можете відслідковувати файли пізніше.

Причина, яку я пропоную зберегти, що один рядок у файлі полягає в тому, що він дає .gitignoreмету. В іншому випадку, хтось із ліній може подумати, щоб його видалити. Це може допомогти, якщо ви розмістите коментар над рядком.


4

Іноді доводиться стикатися з погано написаними бібліотеками або програмним забезпеченням, для яких потрібен "справжній" порожній і існуючий каталог. Якщо встановити простий .gitignoreабо .keepможе зламати їх, це призведе до помилок. Наведене нижче може допомогти в цих випадках, але жодної гарантії ...

Спочатку створіть потрібний каталог:

mkdir empty

Тоді ви додаєте розбиту символічну посилання до цього каталогу (але в будь-якому іншому випадку, ніж описаний вище випадок використання, будь ласка, використовуйте a READMEз поясненням):

ln -s .this.directory empty/.keep

Щоб ігнорувати файли в цьому каталозі, ви можете додати їх у свій корінь .gitignore:

echo "/empty" >> .gitignore

Щоб додати ігнорований файл, використовуйте параметр, щоб примусити його:

git add -f empty/.keep

Після фіксації у вашому індексі перерване символічне посилання, а git створює каталог. Нерозривне посилання має деякі переваги, оскільки це не звичайний файл і вказує на не регулярний файл. Тож він навіть підходить до частини питання "(що не містить файлів)", не за наміром, а за значенням, я думаю:

find empty -type f

Ці команди показують порожній результат, оскільки в цьому каталозі відсутні файли. Тому більшість програм, які отримують усі файли в каталозі, зазвичай не бачать цього посилання, принаймні, якщо вони "існують", або "читається". Навіть деякі сценарії там не знайдуть жодного файлу:

$ php -r "var_export(glob('empty/.*'));"
array (
  0 => 'empty/.',
  1 => 'empty/..',
)

Але я настійно рекомендую використовувати це рішення лише в особливих обставинах, добре написане READMEв порожньому каталозі, як правило, краще рішення. (І я не знаю, чи працює це з файловою системою Windows ...)


4

Читаючи відповіді @ofavre та @ stanislav-bashkyrtsev , використовуючи розбиті посилання на підмодуль GIT для створення каталогів GIT, я здивований, що ще ніхто не запропонував цієї простої поправки до ідеї, щоб зробити цю справу здоровою та безпечною:

Замість того, щоб зламати підроблений підмодуль у GIT , просто додайте порожній справжній .

Введіть: https://gitlab.com/empty-repo/empty.git

Репозиторій GIT з точно одним комітом:

commit e84d7b81f0033399e325b8037ed2b801a5c994e0
Author: Nobody <none>
Date: Thu Jan 1 00:00:00 1970 +0000

Ніякого повідомлення, жодних файлів.

Використання

Щоб додати порожній каталог до GIT repo:

git submodule add https://gitlab.com/empty-repo/empty.git path/to/dir

Щоб конвертувати всі існуючі порожні каталоги в підмодулі:

find . -type d -empty -delete -exec git submodule add -f https://gitlab.com/empty-repo/empty.git \{\} \;

Git зберігатиме останній хеш-коміт при створенні посилання на підмодуль, тому вам не доведеться турбуватися про мене (або GitLab), використовуючи це для введення шкідливих файлів. На жаль, я не знайшов жодного способу примусити, який ідентифікатор комісії використовується під час оформлення замовлення, тому вам доведеться вручну перевірити, чи використовується контрольний ідентифікатор e84d7b81f0033399e325b8037ed2b801a5c994e0комісіїgit submodule status після додавання репо.

Тим НЕ менше не є рідною рішенням, але краще , що ми , ймовірно , може бути без кого - то отримувати їх руки на самому ділі , на самому ділі брудно в кодової GIT.

Додаток: Відтворення цього зобов'язання

Ви повинні мати можливість відтворити цю точну фіксацію за допомогою (у порожньому каталозі):

# Initialize new GIT repository
git init

# Set author data (don't set it as part of the `git commit` command or your default data will be stored as “commit author”)
git config --local user.name "Nobody"
git config --local user.email "none"

# Set both the commit and the author date to the start of the Unix epoch (this cannot be done using `git commit` directly)
export GIT_AUTHOR_DATE="Thu Jan 1 00:00:00 1970 +0000"
export GIT_COMMITTER_DATE="Thu Jan 1 00:00:00 1970 +0000"

# Add root commit
git commit --allow-empty --allow-empty-message --no-edit

Створення відтворюваних GIT-комісій напрочуд важко ...


3

Ви не можете. Це навмисне дизайнерське рішення з боку технічних працівників Git. В основному, метою системи управління вихідним кодом, як Git, є управління вихідним кодом, а порожні каталоги не є вихідним кодом. Git також часто описується як контент-трекер, і знову ж таки, порожні каталоги не є вмістом (насправді навпаки), тому вони не відслідковуються.


60
Я оспорюю цю думку. Структура - це вміст, і все, що ви називаєте, сприяє змісту.
ThomasH

20
Порожній файл також не є вихідним кодом або вмістом. Це просто ім'я. І все ж Git із задоволенням відстежує порожні файли. Я не думаю, що це було навмисним дизайнерським рішенням змусити Git відмовлятися відслідковувати порожні каталоги. Я думаю, що відстеження порожніх каталогів - це функція, яка просто не потребує 99% часу, тому вони не намагалися виконувати зайву роботу, необхідну для правильного її роботи. Git може це зробити, якщо хтось хоче, щоб функція була досить поганою, щоб її реалізувати. Я сумніваюся, що підтримка Git протистоїть такому виправленню, якби це було зроблено правильно.
Дан Ліплення

1
@TobyAllen тут є оновлене посилання на поширені запитання. Найвища відповідь - це також те, що рекомендується в FAQ із більш точними інструкціями.
Даніель Да Кунья

3
Це відсутня функція (і низький пріоритет), а не навмисне обмеження. Із FAQ про Git: Наразі дизайн індексу Git (область постановки) дозволяє лише перелічити файли, і ніхто не достатньо компетентний вносити зміни, щоб пусті каталоги не піклувалися про цю ситуацію, щоб її виправити.
jbo5112

Не дуже згоден. Я можу знайти різні причини, чому я хочу відстежувати порожню папку. Наприклад, я розробляю дуже легку основу PHP MVC для своїх проектів. У мене є конкретні папки для розміщення моделей, поглядів тощо. Коли я створюю новий сайт на основі моєї основи, ці папки порожні, оскільки за замовчуванням немає моделей чи переглядів, але мені потрібна папка, щоб існувати, інакше моя структура виграла не працюй!
Гладен

2

Ви можете зберегти цей код як create_readme.php та запустити PHP- код із кореневого каталогу вашого Git-проекту.

> php create_readme.php

Він додасть файли README до всіх порожніх каталогів, щоб ці каталоги були додані до індексу.

<?php
    $path = realpath('.');
    $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),       RecursiveIteratorIterator::SELF_FIRST);
    foreach($objects as $name => $object){
        if ( is_dir($name) && ! is_empty_folder($name) ){
            echo "$name\n" ;
            exec("touch ".$name."/"."README");
        }
    }

    function is_empty_folder($folder) {
        $files = opendir($folder);
        while ($file = readdir($files)) {
            if ($file != '.' && $file != '..')
                return true; // Not empty
            }
        }
?>

Тоді робіть

git commit -m "message"
git push
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.