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

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

37 ответов

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

touch .keep

В Linux это создает пустой файл с именем .keep, Это имя предпочтительнее .gitkeep поскольку первый является агностиком для Git, тогда как последний специфичен для Git. Во-вторых, как заметил другой пользователь, .git Соглашение префикса должно быть зарезервировано для файлов и каталогов, которые использует сам Git.

В качестве альтернативы, как отмечено в другом ответе, каталог может содержать описательный README или же README.md файл вместо.

Конечно, это требует, чтобы присутствие файла не приводило к поломке вашего приложения.

Зачем нам нужны пустые версионные папки

Перво-наперво:

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

Это просто не будет отслеживаться. Но есть сценарии, в которых "управление версиями" пустых каталогов может быть полезным, например:

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

Некоторые предложенные обходные пути

Многие пользователи предлагают:

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

Хотя оба решения, безусловно, работают, я считаю их несовместимыми с осмысленным подходом к версионированию Git.

  • Почему вы должны поместить поддельные файлы или файлы README, которые, возможно, вам не нужны в вашем проекте?
  • Зачем использовать .gitignore сделать что-то (хранение файлов), прямо противоположное тому, для чего оно предназначено (исключая файлы), даже если это возможно?

.gitkeep подход

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

Хотя это может показаться не такой большой разницей

  • Вы используете файл, цель которого - сохранить папку. Вы не помещаете туда информацию, которую не хотите помещать.

    Например, вы должны использовать README в качестве README с полезной информацией, а не в качестве предлога для сохранения папки.

    Разделение проблем - это всегда хорошо, и вы все равно можете добавить .gitignore игнорировать ненужные файлы.

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

    • Файл, не связанный с кодом (из-за начальной точки и имени)
    • Файл явно связан с Git
    • Его цель (сохранить) четко сформулирована, последовательна и семантически противоположна по своему значению игнорировать

Принятие

Я видел .gitkeep Подход принят очень важными структурами, такими как Laravel, Angular-CLI.

Как описано в других ответах, Git не может представлять пустые каталоги в своей промежуточной области. (См. Git FAQ.) Однако, если для ваших целей каталог достаточно пуст, если он содержит .gitignore только файл, то вы можете создать .gitignore файлы в пустых каталогах только через:

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

Энди Лестер прав, но если ваш каталог просто должен быть пустым, а не пустым пустым, вы можете поставить пустой .gitignore файл там в качестве обходного пути.

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

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

Добавьте файл .gitkeep в этот каталог и зафиксируйте его.

      touch .gitkeep 

do git commit, это стандарт, за которым следует git.

ВНИМАНИЕ: этот твик не работает, как оказалось. Приносим извинения за неудобства.

Оригинальный пост ниже:

Я нашел решение, играя с внутренностями 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 знал о ее существовании и игнорировал ее содержимое, вы можете перейти с этот твик Путь к субмодулям в обычном режиме требует больше шагов, чем этот твик.

Способ создания папки журнала Ruby on Rails:

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

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

Лог-файлы могут быть сохранены путем выдачи,

echo log/dev.log >> .gitignore

но вы, наверное, знали это.

Допустим, вам нужен пустой каталог с именем tmp:

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

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

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

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

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

Итак, поскольку у большинства наших разработчиков уже установлен Ant, я собрал файл сборки, чтобы выполнить это независимо от платформы.

<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Gitkeep" basedir="." default="keep">
    <!--Apply to all subdirs of this dir-->
    <target name="keep" description="-> Add a .gitkeep file to all empty subdir's of this dir.">

        <!--Create a ref to all the subdirs in the tree of this dir-->
        <dirset id="dirs.ref" dir="./" includes="**/*"/>
        <!--Create a list of the subdirs under this dir-->
        <property name="dirs.list" refid="dirs.ref" />

        <!--For each subdir-->
        <for list="${dirs.list}" delimiter=";" param="dir">
            <sequential>
                <!--If the subdir is empty this target will add a .gitkeep file to it-->
                <antcall target="gitkeep" inheritall="false">
                    <param name="dir" value="@{dir}"/>
                </antcall>
            </sequential>
        </for>
    </target>

    <!--Add a .gitkeep file to a directory if it's empty-->
    <target name="gitkeep" description="-> Add a .gitkeep file to a specific subdir of this dir. Use -Ddir=relative/path/to/dir">

        <!--Create a ref of the files inside this dir-->
        <fileset dir="${dir}" id="contents.ref"/>

        <!--Create a path to the contents of this directory, ONLY if it's not empty-->
        <pathconvert refid="contents.ref" property="contents.path" setonempty="false"/>

        <if>
            <!--If the dir is empty create the .gitkeep file-->
            <not><isset property="contents.path"/></not>
            <then>
                <!--Create the .gitkeep file-->
                <echo message="Version this dir in Git even if its empty." file="./${dir}/.gitkeep" force="true" append="false"/>
            </then>
        </if>
    </target>
</project>

Теперь я могу просто бежать

ant -f gitkeep.xml

И это создает файл.gitkeep в любом пустом подкаталоге. Даже в Windows:) Примечание. Для этого файла сборки требуется jar Ant Contrib.

Я продолжаю работать над этой концепцией здесь.

https://github.com/mig82/gitkeep

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

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

Добавить .gitignore файл в ваш пустой каталог:

*
*/
!.gitignore
  • * игнорировать все файлы в папке
  • */ Игнорировать подкаталоги
  • !.gitignore включить файл.gitignore

Затем удалите кеш, добавьте файлы, зафиксируйте и нажмите:

git rm -r --cached .
git add .
git commit -m ".gitignore fix"
git push

Вы не можете и, к сожалению, никогда не сможете. Это решение принял сам Линус Торвальд. Он знает, что хорошо для нас.

Где-то где-то я читал напыщенную речь.

Я нашел Re: Пустые каталоги.., но, возможно, есть еще один.

Вы должны жить с обходными путями... к сожалению.

Я тоже столкнулся с проблемой с пустыми каталогами. Проблема с использованием файлов-заполнителей заключается в том, что вам нужно создавать их и удалять их, если они больше не нужны (потому что позже были добавлены подкаталоги или файлы. С большими деревьями исходного кода управление этими файлами-заполнителями может быть громоздким и приводить к ошибкам. склонный.

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

Просто взгляните на: http://code.google.com/p/markemptydirs

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

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

Нет способа заставить Git отслеживать каталоги, поэтому единственное решение - добавить файл-заполнитель в каталог, который вы хотите отслеживать в Git.

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

Префикс . помечает его как скрытый файл.

Другой идеей было бы добавить README файл, объясняющий, для чего будет использоваться каталог.

Многие уже ответили на этот вопрос. Просто добавьте сюда версию 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}

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

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

Я вставил это в Rakefile для быстрого доступа.

Решение Джейми Флурной прекрасно работает. Вот немного улучшенная версия, чтобы сохранить .htaccess:

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

С помощью этого решения вы можете зафиксировать пустую папку, например /log, /tmp или же /cache и папка останется пустой.

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

Если вы хотите добавить папку, которая будет содержать много временных данных в нескольких семантических каталогах, то один из подходов заключается в том, чтобы добавить что-то подобное в корневой каталог.gitignore...

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

Затем вы можете зафиксировать описательные файлы README.md (или пустые файлы, не имеет значения, если вы можете назначить их уникально, как с помощью *.md в этом случае) в каждом каталоге, чтобы убедиться, что все каталоги остаются частью репозитория, но файлы (с расширениями) игнорируются. ОГРАНИЧЕНИЕ: .не допускаются в именах каталогов!

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

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

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

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

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

Неустранимый: недопустимое имя объекта b64338b90b4209263b50244d18278c0999867193

Я бы не советовал использовать его, поскольку он может перестать работать в будущих версиях Git. Что может привести к повреждению вашего хранилища.

Легкий способ сделать это - добавить .gitkeep файл в каталог, который вы хотите (в настоящее время) оставить пустым.

См. Этот ответ SOF для получения дополнительной информации, который также объясняет, почему некоторые люди находят конкурирующее соглашение о добавлении файла.gitignore (как указано во многих ответах здесь) запутанным.

Иногда вам приходится иметь дело с плохо написанными библиотеками или программным обеспечением, которому нужен "настоящий" пустой и существующий каталог. Выкладываю простой .gitignore или же .keep может сломать их и вызвать ошибку. Следующее может помочь в этих случаях, но без гарантии...

Сначала создайте нужный каталог:

mkdir empty

Затем вы добавляете неработающую символическую ссылку в этот каталог (но в любом другом случае, кроме описанного выше варианта использования, используйте 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...)

Ты не можешь Это намеренное дизайнерское решение разработчиков Git. По сути, целью системы управления исходным кодом, такой как Git, является управление исходным кодом, а пустые каталоги не являются исходным кодом. Git также часто описывается как трекер контента, и опять же, пустые каталоги не являются контентом (скорее наоборот), поэтому они не отслеживаются.

Другие вопросы по тегам