Как я могу добавить пустой каталог в Git-репозиторий?


4268

Как я могу добавить пустой каталог (который не содержит файлов) в репозиторий Git?


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

335
@ два Я, например, не согласен, что это бесполезно. Ваша иерархия каталогов является частью вашего проекта, поэтому она должна контролироваться версией.
JBentley

114
В моем случае я хотел бы добавить структуру каталогов для файлов tmp, но не сами файлы tmp. Благодаря этому мой тестер имеет правильную структуру (в противном случае возникают ошибки), но я не забиваю свои коммиты данными tmp. Так что да, это полезно для меня!
Адам Маршалл,

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

31
Почему бы не создать процедуру, которая создает файлы tmp, и создать каталог tmp?
RyPeck

Ответы:


4128

Другой способ сохранить каталог (почти) пустым (в хранилище) - создать в .gitignoreэтом каталоге файл, содержащий следующие четыре строки:

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

Тогда вам не нужно правильно оформлять заказ, как в решении m104. .

Это также дает то преимущество, что файлы в этом каталоге не будут отображаться как «неотслеживаемые», когда вы выполняете состояние git.

Сделать комментарий @GreenAsJade постоянным:

Я думаю, что стоит отметить, что это решение делает именно то, о чем просил вопрос, но, возможно, это не то, что искали многие люди, смотрящие на этот вопрос. Это решение гарантирует, что каталог остается пустым. Он говорит: «Я действительно никогда не хочу, чтобы файлы проверялись здесь». В отличие от «У меня пока нет файлов для проверки, но мне нужен каталог здесь, файлы могут появиться позже».


25
Я думаю, что решение README, предложенное @JohnMee, должно использоваться вместе с этим; файл .gitignore содержит объяснение того, что мы хотим не допускать в управлении версиями, в то время как файл README объясняет назначение каталога, которые являются очень важной частью информации.
Педроманоэль

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

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

6
Это идеально подходит для кеш- папок.
благоухающий

10
К сожалению, это приводит к непустому каталогу, у него есть один скрытый файл.
Pedorro

1091

Ты не можешь Смотрите Git FAQ .

В настоящее время дизайн индекса git (промежуточной области) разрешает только перечисление файлов, и никто, достаточно компетентный, чтобы внести изменения, чтобы пустые каталоги могли достаточно позаботиться об этой ситуации, чтобы исправить ее.

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

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

Если вам действительно нужен каталог для оформления покупок, вы должны создать в нем файл. .gitignore хорошо работает для этой цели; Вы можете оставить его пустым или указать имена файлов, которые вы ожидаете увидеть в каталоге.


67
Ниже ответ НАМНОГО лучше. Тот факт, что git низкоуровневого программного обеспечения не позволяет, для меня не так важно, как на самом деле использовать Git, когда мне нужен пустой каталог. Добавление 2 строки .gitignore кажется мне приемлемым.
Амала

1
Хорошо, если кто-то хочет переместить файлы в новый каталог, он не сможет это сделать, git mvпоскольку git будет жаловаться, что новый каталог не находится под контролем версий
lulalala

16
Вы можете прочитать « это невозможно, вы не можете и т. Д. » По всему Интернету на этот частый вопрос. .gitignoreТрюк является частым ответом, и удовлетворяет многие потребности. Однако возможно сделать git track действительно пустым каталогом, смотрите мой ответ
ofavre

2
Хотя чем больше я об этом думаю, тем больше похоже на то, что «SHA-хэш пустой строки», если он существует, фактически будет четко определенным идентификатором для пустого дерева, если только невозможно определить, является ли этот объект дерево или капля
Эмиль Лундберг

21
Я видел много репозиториев, в которых используется пустой файл, предназначенный .gitkeepдля этой цели.
Sukima

759

Создайте пустой файл с именем .gitkeepв каталоге и добавьте его.


58
Я добавил ответ, поощряющий создавать .keepвместо.
Acumenus

206
.gitkeepне было предписано Git и заставит людей вторично угадать его значение, что приведет их к поискам в Google, которые приведут их сюда. Соглашение о .gitпрефиксе должно быть зарезервировано для файлов и каталогов, которые использует сам Git.
t-mart

10
@ t-mart " .gitПрефиксное соглашение должно быть зарезервировано ..." Почему? Git запрашивает это бронирование?
Ограниченное искупление

9
В этом случае файл READMEили был ABOUTбы таким же хорошим или лучшим. Оставить записку для следующего парня, как мы все делали до URL.
Дейв

5
Не работает, если вы пишете модульный тест, который должен тестировать код в пустой директории ...
thebjorn

437

Вы всегда можете поместить файл README в каталог с объяснением, почему вы хотите этот, иначе пустой каталог, в репозитории.


39
+1, Хорошее предложение, пустой каталог не имеет никакого смысла, если он не будет использоваться в будущем. Поэтому создайте файл README внутри него и напишите, для чего этот каталог, и какие файлы будут помещены туда в будущем. Это решает обе проблемы.
saeedgnu

63
@ilius Ерунда. Структура каталогов, содержащая пустые каталоги, может быть очень желательна во многих ситуациях (например, приложение MVC, где вы хотите каталог моделей, но еще не удосужились создать какие-либо модели, или каталог общих представлений, в который вы планируете добавить общие представления позже. ). Более того, вставлять README в каждую из них - излишне, так как очевидно, для чего они существуют, и легко забыть поместить README в каждую из них. И вы должны помнить, чтобы удалить README, когда вы добавите к ним некоторые другие файлы. По сути, git должен разрешать пустые каталоги.
Еж

20
@Jez: я не согласен. Дело в том, что git предназначен для контроля (и индексации) исходного кода. Важно, что идентификатор коммита - это хеш содержимого. То есть оно должно иметь содержание. Вам не нужно README в каждой части дерева, только листовые узлы. Если у вас есть места, в которые вы намереваетесь поместить код, но не код, и вы даже не будете тратить время на вывод «место для моделей» >> README, то у вас есть идея, а не коммит. Гит не интересен. Сказать «я хочу, чтобы у запущенного приложения были пустые каталоги XYZ» - проблема времени выполнения , а не проблема источника. Обращайтесь с вашим установщиком.
Джо Ацбергер

6
@JoeAtzberger Это отсутствующая функция, а не намеренное ограничение. Из Git FAQ: В настоящее время дизайн индекса Git (промежуточной области) позволяет только перечислять файлы, и никто, достаточно компетентный, чтобы внести изменения, чтобы пустые каталоги могли позаботиться об этой ситуации, не позаботился об этом.
jbo5112

7
@ jbo5112 Да, «специальный код», на который вы ссылаетесь, это «установщик», о котором я упоминал. Ваша установка веб-приложения уже должна обрабатывать создание базы данных, локальную конфигурацию, вытягивание зависимостей или 100 других операций, но пара пустых каталогов выходит за рамки этого? Попробуйте gradle, passenger, chef, примитивный Makefile и т. Д. Нет никакой разницы в безопасности между созданием каталогов и другой (потенциально гораздо более сложной / опасной) работой по установке приложения. И если у вас действительно нет deps, config, DB и т. Д., И нет установщика, тогда просто используйте README. Ни один случай не требует от вас обоих.
Джо Ацбергер

349
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"сделать это во всех неотслеживаемых пустых каталогах.
Acumenus

1
Не нравится это решение, трудно угадать, что делает этот файл. Кроме того, если вы генерируете файлы в своей среде разработки (например, журналы или изображения и т. Д.), Это не удерживает эти файлы от создания версий и их запуска в производство, что нехорошо.
danielrvt

1
Windows не любит файлы без имен и требует для этого особой магии (так называемое терминальное приложение bash или аналог).
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 игнорирует их )
blueFast

45
@Behnam: я возьму понижение, но мое исследование мета SO не показывает интереса к подробным ответам, поскольку они предоставляют достаточно деталей и ясности, чтобы быть полезными для каждого читателя (и каждого уровня квалификации). Тем не менее, я очень открыт для любой критики, и спасибо, что публично объявили причину, я воспринимаю это очень позитивно.
Cranio

4
Если вы отредактируете свой ответ, чтобы заменить его .gitkeepлюбым другим именем файла без префикса git, вы получите мое возражение, я думаю, что этот ответ является лучшим и наиболее информативным. Причина: я думаю, что ".git *" должен быть зарезервирован для файлов, предписанных git, в то время как это просто заполнитель. Мое первое предположение, когда я увидел, что, например, файл «.gitkeep» будет автоматически игнорироваться (это было бы неплохо), но это не так, верно?
Джонни

5
Интересно, почему людям так трудно понять, почему кто-то хочет добавить «пустые» папки в git. Вы должны начать где-нибудь, верно? Итак, обычно вы начинаете со структуры папок ваших проектов и - увы - в начале проекта там еще ничего нет. После завершения репо проекта работники команды могут клонировать и начать работать над той же структурой.
BitTickler

127

Как описано в других ответах, Git не может представлять пустые каталоги в своей промежуточной области. (См. Git FAQ .) Однако, если для ваших целей каталог достаточно пуст, если он содержит .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
Это именно то, что я сказал. Оба параграфа рассмотрены во фрагменте часто задаваемых вопросов, которые я разместил.
Энди Лестер

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 не отслеживает пустые каталоги. Смотрите Git FAQ для более подробного объяснения. Предложенный обходной путь - поместить .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 игнорировать его (и все остальное в пустом каталоге).


12
Две вещи: вы можете просто "echo" * '> 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?AmericanCulturalAssuming
клик

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каталог изначально не существует. Он больше не будет сломан, как только вы сделаете свою сборку.
Нобар

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
Я знаю, что вы опубликовали это как пример плохого аргумента, но я ценю ссылку, потому что это на самом деле аргументированный аргумент против отслеживания каталогов. ;-)
глэк

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

Патрик, он также использует слово «идиот» там. Я подозреваю, что его формулировка адресована людям, находящимся здесь, в этой теме, и поэтому я предполагаю, что он сам не внедрит что-то «идиотское» в Git.
user2334883

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. Пример: если в программном обеспечении есть каталог для лог-файлов (например, oxishop), который не должен быть доступен через Интернет, в каталоге есть .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
Йохен Шульц

7

Вот взлом, но забавно, что он работает (Git 2.2.1). Подобно тому, что предложила @Teka, но легче запомнить:

  • Добавить подмодуль в любой репозиторий ( git submodule add path_to_repo)
  • Это добавит папку и файл .submodules. Зафиксируйте изменения.
  • Удалите .submodulesфайл и подтвердите изменение.

Теперь у вас есть каталог, который создается при извлечении коммита. Интересно то, что если вы посмотрите на содержимое объекта дерева этого файла, вы получите:

Неустранимый: недопустимое имя объекта 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в данном случае -) в каждом каталоге, чтобы убедиться, что все каталоги остаются частью репо, но файлы (с расширениями) игнорируются. ОГРАНИЧЕНИЕ: .не допускается в именах каталогов!

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

Нет необходимости дополнительно изменять .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-репозиторий:

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), используя это для внедрения вредоносных файлов. К сожалению , я не нашел путь к силе, совершение ID используется во время проверки, так что вам придется вручную проверить , что ссылка фиксации идентификатора с 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 . Верхний ответ - также то, что рекомендовано FAQ с более точными инструкциями.
Даниэль Да Кунья

3
Это отсутствующая функция (и низкий приоритет), а не намеренное ограничение. Из Git FAQ: В настоящее время дизайн индекса 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.