Как стать автором
Обновить

Комментарии 140

Вопрос позвольте-с. Что такое храните Вы на Гитхабе (ну или не лично Вы храните, а кто-то другой хранит нужное Вам — это не составляет особенной разницы), для чего пятидесяти мегабайтов не будет достаточно?

(На самом деле речь идёт даже и не о пятидесяти, а о сотне мегабайтов, насколько я понял первоисточник. После пятидесяти ограничатся предупреждением, а после сотни станет происходить отказ в публикации или правке.)
На ум приходят только всякие бинарники: коллекция фотографий в приватном репозитории (кто-то решил, что гит существует для этого), ресурсы для движков игр. Даже тут где-то была статья о том, как хранить свои фотографии в гите.
Да вы правы для 100 мегабайт, не верно прочитал с утра.
Инсталлятор может быть больше по размеру. chrome\src\out\Debug\mini_installer.exe — 446.8Mb, unit_tests.exe — 169.2Mb, webkit.dll — 144.3Mb. Релизные версии, правда, меньше должны быть.
Это да, вот только ИМХО инсталяторам нету места в системах контроля версий. Они абсолютно автономные и должны складываться в других местах, а сопаставляться с исходными кодами по тэгам и/или веткам. В репозиторий лучше добавить скрипт для создания инсталятора.
Я помню времена когда говорили «одна игра ЦЕЛУЮ дискету занимает. дожили!».
Потом через несколько лет фраза повторилась в плане CD и так далее.

Технология предоставляет, потребители потребляют.
Что бинарник делает у вас в системе контроля версий исходного кода?
У всех цели разные.
Например, я знаю конторы, которые держат бинарники в контроле версий (внутренний репозиторий, а не Github, конечно). Очень удобно устанавливать новые версии в production и особенно откатываться назад когда нужно.
Да, такое много где можно встретить. Это называется legacy, и это то, от чего надо уходить. Потому гитхаб все правильно сделал. Цели тут не разные, тут ошибка архитектуры проекта. С репозитариями бинарников все так-же удобно устанавливать новые версии в продакшн и откатываться когда нужно. Даже еще удобнее.
Верно. Для репозитория бинарников используют тот же version control.
Да вы что такое говорите. Механизмы версионирования бинарников абсолютно другие. Текстовые дельты абсолютно не применимы к бинарникам. Хранить бинарники в SCM типо SVN/Git/Mercurial — нагружать сервер лишними обработками, поскольку там не хранятся файлы, там хранятся дельты от самого рождения репозитория. Когда делают клон репозитория, это процесс воссоздания наложения дельт друг на друга с момента рождения репозитория в локальной папке. Бинарники в случае с Nexus/Artifactory (да даже линусковыми apt/yum) храняться как файлы, каждая версия в своем каталоге. Объеденины мета-данными и индексными файлами, где указаны контрольные суммы, версии и так далее. Отдаются как статик ресурсы по http или другому протоколу. Чувствуете разницу?
Их не надо сравнивать, их надо хранить и иметь к ним label или revision, которые будут соответствовать определенным версиям продукта.
В репозитории можно хранить файлы целиком без дельты, некоторые version control это позволяют.
А по поводу нагружать сервера… Сервера нужны что бы ими пользоваться. Даже если держать где-то rpm, то это тоже надо нагружать сервер. А с rpm тут еще сложнее заменить файлы частично или, например, сделать diff конфига от разных релизов.
Есть большая разница, нагружать сервер передачей файлов, или просчитыванием дельт внутри них. Каждый инструмент должен использоваться для того, для чего он предназначен. Рекомендую ознакомиться с github.com/about (ключевое слово code) прежде, чем хаять гитхаб за закручивания гаек.
Я не вижу где я хаю Github за что либо. Я просто рассказываю про еще один use-case для version control, который достаточно популярен. Я даже не привязываюсь к определенной системе контроля версий в этом случае, так как тут может выступать не только git.

Как я уже уточнил выше, дельту высчитывать не обязательно в случае с бинарниками. Надо просто хранить эти бинарники и иметь к ним label или номер ревизии, по которым можно делать установку.
Для этого достаточно многие version control хранят бинарники в чистом виде, а не в виде дельты. А если нет дельты, то и не надо ее пересчитывать.
Не надо переживать за чужие сервера.
Отлично, храните бинарники в другом месте, привязывайте их декларативно в исходниках с помощью менеджера зависимостей (maven, gradle и прочие для джавы). В чем проблема? Ваш юз кейс очень плохой с моей точки зрения, карать за такое надо, потому что позвольте, но все же мы говорим здесь про гитхаб, а не абстрактно про системы контроля версиями. Ибо и правда, есть системы контроля версиями (тот же Nexus или Artifactory), а есть системы контроля версиями исходного кода. Github это именно второй сервис, и не забываем, что к одному и тому-же репозиторию он предоставляет доступ по svn, git, hg и, возможно, другим протоколам. Особенно ввиду SVN доступа должно становится понятно введение такого лимита.
Насколько я знаю, в git храняться сжатые blob’ы: полные версии файлов. Никаких дельт. В Mercurial действительно дельты, но есть largefiles, хранящий бинарные файлы отдельно и без дельт. Про subversion не знаю.
Предположим у нас 10 ревизий, в каждой ревизии вы добавляеете файл на 10 гигов, и удаляете такой-же файл (но другой) из предыдущей ревизии. Делая клон такого репо с ревизией #10 вы вытянете по сети 100 гигабайт данных (все 10 файлов), не смотря на то, что вы выбрали конкретную десятую ревизию. Экономией в следствии сжатия блобов я принебрег, ибо для примера это не существенно. Вы все еще утверждаете, что система версионирования кода подходит для аналогичных целей в отношении к бинарникам?
Да. Система контроля версий, не git. В mercurial с включённым largefiles вы гоняете только хэши бинарников и те версии бинарников, которые вам необходимы в данный момент. В subversion вы тоже гоняете только необходимые версии. У largefiles есть локальный кэш, у subversion вроде тоже (но точно не скажу), поэтому даже необходимые версии может оказаться не нужным гонять.

Другое дело если бинарники не являются необходимыми для сборки. Но это вопрос организации разделения на репозитории, не вопрос того, подходят ли системы контроля версий для хранения бинарников.

// Кстати, с бинарниками и сжатием есть как всегда возможность получить overhead вместо сжатого файла. Так что я даже и не думал говорить о том, что наличие сжатия может сделать конкретную СКВ пригодной для хранения бинарных данных.
Не вижу разницы между тем, нужны ли бинарники для сборки проекта или нет. Я не хочу их загружать в мой девелопмент энвайрмент для фикса, ибо после коммита проект все равно будет собираться на CI сервере, а не локально. Смотрите развернутый ответ здесь. habrahabr.ru/post/184248/#comment_6407226

С largefiles я не знаком, но судя по вашему описанию, это огромный костыль, который ломает всю основную архитектуру mercurial, когда каждый локальный клон является самостоятельным репозиторием. Т.е. я сделал чекаут (клон) какой-то ревизии, и все предыдущие ревизии ко мне попали только в виде какого-то хэша, и я не могу оперировать потом репозиторием локально в оффлайне (если только Бабушкин таки не научился «распаковывать» хэш). И других клонов со своего клона я не могу сделать.
Это так (на их сайте написано, что это «feature of last resort»). Но с subversion вы тоже не сможете работать с другими ревизиями в оффлайне. Другие клоны сделать сможете, но не сможете получить на них ревизию, файлов для которой нет в кэше.

Только на ситуацию мы смотрим с несколько разных сторон. Вы, похоже, работаете в компании, а я в основном работаю с СПО в свободное время. Поэтому CI сервера либо нет, либо это travis, который при всех своих достоинствах будет собирать намного медленнее, чем это возможно на моей машине. Поэтому получать необходимые для сборки файлы из ещё одного репозитория мне не очень удобно. Поэтому я так рекламирую largefiles, несмотря на то, что сами разработчики обозвали её «feature of last resort».
Ну, разумеется, сабвершн же централизованный. А мы говорим про костыль, делающий таким-же изначально децентрализованную систуму.

Да, я работаю в компании, но все-так же обожаю СПО, как и раньше. Потому у меня есть отдельная машинка в качестве билд-сервера, CI сервера, хранилища бинарников.
Макеты фотошопа, например. Они порой намного больше занимают, чем 100 мегабайт. Наверняка есть какие-то иные специализированные решения, но у нас в компании требования хранить все исходники (включая исходники графики) в одном месте.
Простите, но гитхаб все-таки предназначен для кода, исходного кода. Программ. А не фотошоповских макетов. Если руководство вашей компании этого не понимает, это не проблемы гитхаба.
Но исходники проекта это не только исходный код. Это макеты фотошопа, 3Д модели, наборы текстур, шрифты, маски, сторонние бинарные библиотеки. Буду весьма вам признателен, если вы посоветуете систему, которая предназначена для всего этого, раз по-вашему мнению гитхаб на это не тянет.
Установите локальную версию репозитория — это займет несколько минут. Подключить прямой IP — тоже плевое дело. Винчестеры сейчас стоят копейки, 80 баксов за террабайт и меньше.

Как вариант — свой дедик, от 20 евро в месяц. И никто ни в чем почти не будет вас ограничивать.
Не хочу обижать тут дизайнеров и прочие профессии, но гитхаб предназначен для хранения исходного кода. Для программистов. Я не могу посоветовать вам сервис, поскольку я программист, а не дизайнер (или как вы там еще называетесь). Не любой текстовый файл является исходным кодом. Если текстовый файл, занимающий более 100МБ может быть открыт в текстовом редакторе, это еще не значит, что он подлежит версионированию в системе контроля исходного кода. Рекомендую ознакомиться, для чего предназначен гитхаб: github.com/about
Bitbucket
У вас немного перемешались понятия «исходный код» и «система контроля версий».
Git — это система контроля версий, не только исходный код. То что там github написал у себя на странице about — это рекламный материал, и значение никакого не имеет, ведь все знают что GitHub — это хостинг гит репозиториев.

В т.ч. и программистам, приходится, иногда, вместе с кодом хранить в одном репозитории картинки и прочие медиафайлы.
Вы глубоко заблуждаетесь, как я написал выше, гитхаб предназначет для исходного кода и только, и уж вовсе не является хостингом git репозиториев, ибо предоставляет доступ к одним и тем-же репо для git, hg и svn клиентов. Вы еще по svn хотите бинарники гонять?

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

Вообще то это получше чем в Git будет: 1) бинарные файлы не мерджаться, значить пригодиться lock 2) можно сделать чекаут определённое ревизии/поддиректории, уменьшив в разы размер чекаута.
Потом из-за таких как вы, у нас корпоративный сервер SVN на кластере в 64 ядра и 512 гигах оперативки еле крутиться (я уж молчу за съеденное место большущего стораджа).
Так это… не надо было в него пихать столько файлов… :)
Так вы же сами предлагаете делать именно так!
Пихать в SCM очень много файлов, так что кластер в 64 ядра еле крутится? Нет я такого не предлагал.
А вы представьте себе очень большую мировую контору, где овер 30к программистов, и в каждой команде считают, что 5-10 файлов бинарных в репозитории не помешают.
И, не забывайте, что гитхаб дает svn доступ, но под этой маской это все тот-же гит. И это преобразование он делает на своей стороне за счет своих вычислительных ресурсов.
Исходный код не может содержать ни изображений, ни видеофайлов, ни баз данных, ни каких-либо других бинарных данных? Упс, 95% моих проектов не подходят. :(
Почему бы тогда гитхабу не поставить автоматический reject на .jpg, *.png, *.dll и прочее? Думается, они так делать всё-таки не будут, т.к. их понимание предназначения гитхаба всё-таки отличается от вашего.

А вообще, неплохой слоган бы вышел: «Если у вас в проекте хотя бы один бинарный файл, вам не место на гитхаб, уходите на Bitbucket». :)
Потому, что мы живем в то время, когда подобные стандарты и методологии только девелопятся. Есть море legacy кода и проектов, где все эти ресурсы таки находятся в репозитории с сорцами, и эту ситуацию не исправить в один день запрещением заливать их на гитхаб.
Вы путаете светлое будущее, к которому надо стремиться, с категоричностью запретов.
Вы очень обижаете ребят из www.kaleidoscopeapp.com/ Они пилят свою утилиту для сравнения файлов с завязкой на контроль версий и упор на картинки и макеты из фотошопа.
Я не понимаю, чем я их обижаю.

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

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

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

Ну ведь вилкой тоже суп кушать можно. Но как-то не удобно.
Вполне размуное решение. Для исходников 100 мегабайт на файл — это руки оторвать программистам. А смысл хранить бинарники под контролем версий? Для этого хватает других сервисов.
Теоретически можно вообразить себе употребление стомегабайтового файла для целей беспрерывного тестирования (continuous integration). Тесты же многие хранят в репозиториях (причём в тех же репозиториях, что и основной код) и обновляют по мере обновления основного кода.

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

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

В частности, в только что рассмотренном нами примере можно в репозитории хранить не стомегабайтовый образец целиком, а один только хэш его; и итог тестового прогона сравнивать с ним, соответственно, не побайтово, а хэшировать сперва — и затем хэши сравнить.
гонять сотни мегабайт по сети при каждом pull/push не выход, так что да, такую ситуацию с картинками нужно оптимизировать однозначно.
Так пул пуш гоняет тока изменения.
В бинарниках?
В том смысле что он не гоняет файлы которые не менялись.
А что вы часто меняете бинарники?
вообще не использую, за редким исключением вроде картинок для макета. где-то 100 мб может и нужно, но имхо — это перебор. Это я бы сказал звоночек, что что-то в проекте идет не так, как надо. Ну или повод задуматься об оптимизации или улучшении
Фотографии и другие данные, нужные для тестов, это ресурсы, а не исходный код. Им не место в SCM.
Фикстурам и данным для тестов не место в SCM ?? А где-же им место тогда? (я, правда, не утверждаю, что 100мб фикстуры это удачная идея)
Да, давайте еще portable версию какого-нибудь mysql засовывать в SCM, нужно для тестов же. Еще раз повторюсь, для этого существуют репозитории для бинарников, менеджеры зависимостей, системы сборки проектов и CI серверы. А уж про тестовый environment вы точно должны были слышать.
давайте еще portable версию какого-нибудь mysql засовывать в SCM, нужно для тестов же

Не вижу связи между тестовыми данными и дистрибьютивом mysql

репозитории для бинарников

ага, туда и нужно помещать все картинки вебсайта? на которые есть ссылки непосредственно из кода (а не из базы данных) типа logo.png menu_*.png? Пойду расскажу об этом моим пяти предыдущим работодателям. И трёх моих предыдущих попрошу все rails фикстуры, конфиги, yaml файлы с переводом срочно вынести в репозиторий для бинарников.

менеджеры зависимостей

системы сборки проектов

CI серверы

Это тут причём?
Вам бы книжку почитать, умную, ибо я не намерен заниматься вашим образованием (бесплатно). Работадатели не мирового уровня пытаются на всем сэкономить, так что не засчитано про ваших предыдущих пятерых. Legacy кода везде хватает, но это не означает, что вот так правильно.
Ладно, с portable версией mysql перегнул. Но вы все равно предлагаете дампы баз с тестовыми данными хранить в репозиториях исходного кода? Хотя, и так вижу, что предлагаете.
Вы спрашиваете, предлагаю ли я картинки и прочее хранить отдельно от кода, когда есть прямые ссылки на них? И сразу же спрашиваете, причем тут менеджеры зависимостей, системы сборки проектов и CI серверы? Ну хватит уже позориться, право, мне за вас уже стыдно. Выучите для начала, что есть все эти умные названия, и потом поймете, возможно, к какой структуре проекта надо стремиться.
Но вы все равно предлагаете дампы баз с тестовыми данными хранить в репозиториях исходного кода?

Нет, где я предлагал дампы баз данных хранить в SCM?

Может Mithgol предлагал? habrahabr.ru/post/184248/#comment_6404954

Нет, не предлагал.

Работадатели не мирового уровня пытаются на всем сэкономить

Надо завести отдельный репозиторий для favicon.ico! Хватит экономить!

потом поймете, возможно, к какой структуре проекта надо стремиться.

Уже понял, чего реально стоит опасаться — enterprise головного мозга.

p.s.
А зачем, кстати, git различает binary и текстовые файлов — для legacy проектов?
Что же для вас «данные для тестов»? Картинки? Не вижу разницы в тестовой картинке и тестовом дапме базы, как ресурса для тестов.

Он их не различает, но способ вычисления дельты, используемый в git, слабо подходит для бинарников. Ибо предполагает генерацию человекочитаемых дельт, коими не являются дельты бинарных файлов.

И причем тут энтерпрайз? По моему тут сейчас вопрос здравого смысла.
Где я сказал про дельты для бинарников? Я пытаюсь донести, что версионировать бинарники в гите как-то не удобно. Потому что кучу фич этого гита к бинарникам просто не применить. Есть куча гораздо более удобных способов версионировать бинарники.
О, да я работаю в не менее крупной и известной конторе, и поверьте, у нас тоже все устроенно именно так. Но, как я сказал выше, мы живем в то время, когда подобные стандарты и методологии только девелопятся. Есть море legacy кода и проектов, где все эти ресурсы таки находятся в репозитории с сорцами, и эту ситуацию не исправить в один день запрещением заливать их на гитхаб.
Вы путаете светлое будущее, к которому надо стремиться, с категоричностью запретов.
Вы не правы. Возьмём обычный кейс — web приложение, которое делают пачка прогеров и верстальщик. Предположим макеты и все доки сложили в wiki — это норм.
Но где хранить картинку-фон менюшки? Где хранить аватарку для свежезареганного пользователя? Где хранить фикстуры с данными, необходимыми для запуска локальной копии проекта?

И + после каждого пуша у нас срабатывает пост-пуш тригер и jenkins прогоняет тесты. Для тестов нужны фикстуры. Фикстуры зависят от модели данных и меняются вместе с ней. Где тогда их хранить?
Можно очень долго спорить о том, как правильно. И у каждого будет свое мнение.
Картинки в другой репозиторий бинарников. Фикстуры, смотря что они из себя представляют. Если это какие-то xml или sql дампы, можно положить их в тот-же git, но в другой репозиторий. Хранить их там, завести на них отдельный билд в дженкинсе, собирать в артифакт и подтягивать зависимостью к коду со скоупом=test.
Напрмире, фикстура — json, для тестирования формирования годовой отчётности. Ради хранения этой фикстуры заводить отдельный репозиторий?
И для картинок по 5кб тоже отдельный?
Не попахивает ли это ненужным усложнением разработки?
Один json файл? Нет, не думаю что это рационально. Он меньше 100МБ? Вообще не стоит беспокоиться. Но в идеологию такое исключение из правил не вписывается, согласитесь.
а у нас инсталлятор mysql лежит в локальном svn. и сдк жавы там же и монгодб и небо и аллах :3
грустно, но к сожалению не шутка и изменений в ближайшем будущем не предвидится. :)
Для того, чтобы убрать эти файлы из репозитория, ограничения в 100 МБ совершенно недостаточно. В таком случае, если ограничение на размер самого репозитория позволяет (а оно позволяет, иначе файлы бы там не лежали), мне было бы проще просто порезать большие файлы с помощью split и собирать обратно на CI сервере нежели использовать хэш и хранить исходные файлы (если, конечно, они тоже превышают данный размер) где‐то ещё.

То есть запретить такие файлы можно. Но максимум, чего вы добьётесь — «заставите задуматься». Во всех случаях хранения таких файлов в git, которые я могу себе представить, может быть использована резка их splitом с последующей склейкой перед использованием, а то и вовсе без оной.
Как раз задуматься она и предназначена. Может, вы делаете что-то не так? ;)
Сотни мегабайт будет достаточно всем, ага :)

А смысл хранить бинарники под контролем версий? Для этого хватает других сервисов.
Т.е. если у вас в веб-приложении используются картинки (бинарники же!), то вы храните их не с проектом, а на сервисах для хранения бинарников, типа мегааплоада или рапидшары? :)

У меня из проекта в проект кочуют юникодные файлы шрифтов по 10-20 мегабайт — использую с PDFLib. Это пока самые большие бинарники, которые я храню в системе контроля версий — для удобства, чтобы сделал чекаут или экспорт, и хоть сразу на продакшен — все необходимые файлы на месте.
У вас на сайте используется картинка в 100 мегабайт? Не говорите адрес, я туда не пойду никогда. :) В остальном, как вы говорите — вам хватает. Github вполне закономерно оптимизирует свои затраты. Я думаю, они проанализировали не одну тысячу реп, прежде чем принять решение, какой размер ограничить.
Вы же говорили о бинарниках вообще, а не о бинарниках меньше 100 МБ :)
Все верно, любым бинарникам не место в SCM, только причем тут рапидшара итд? Бинарники должны попадать в проект на этапе сборки (привет, пхпшники). И брать их можно из репозитария бинарников. Для джавы это Nexus, Artifactory и еще несколько других примеров.
Ну в некоторых случаях бинарники можно запихать. Но это как правило мелкие вещи. Другое дело, я не понимаю что такого запихать в бинарник, чтобы это был именно бинарник, а не сборка исходного кода и почему этот бинарник весом 100 мегабайт нужно пихать в систему контроля версий.
Можно, но не нужно. Как сказали выше, это звоночек, что что-то идет не так. У меня например в одном джава проекте с maven сборкой бинарник protobuf.exe лежит прямо в репозитории. Плохо, да, но пока руки не дойдут запаковать его в отдельный артифакт и задеплоить на нексус.
любым бинарникам не место в SCM

1) HTML-проект с несколькими картинками, хостится через GitHub Pages.
Расскажите, как оптимизировать эту ужасную архитектуру? Добавить репозитарий бинарников? Систему сборки проектов? Менеджеры зависимостей? CI сервер?
2) GUI-библиотека. Для использования достаточно git clone --depth=1 и добавить папку в проект.
Расскажите, как избавиться от этого безобразия? Сколько сущностей добавить, чтобы использовать библиотеку стало наконец удобно?

Быть может, прежде чем делать категоричные заявления, стоит задуматься, что есть море use case'ов отличных от вашего, чтобы не получился, как упомянули выше, энтерпрайз головного мозга.
1. GitHub Pages это сервис, специально созданный для этого. И там не будет монстров, там не построить море функционала, там ничего толком не сделать. Ну захостить парочку статик html страничек с описанием проекта… Вся эта система подходит для страничек-визиток, и нечего тут оптимизировать. Ну только если вы не хотите выкладывать какие-то гиговые видеоролики через GitHub Pages.
2. Что за GUI библиотека? --depth такой-же костыль, как и largefiles в mercurial, ломающий всю децентрализованность.

Я пока еще не увидел ни одного юзкейса, после которого я бы сказал, да дейсвительно, в этом случае нужно хранить бинарники вместе с исходниками.
1. GitHub Pages это хостинг, а исходники лежат в обычном репозитории гитхаб, причем вместе с картинками. Как это не стоит это оптимизировать, там же, о ужас! — бинарники.
2. Любая GUI библиотека, использующая изображения. Вот первая попавшаяся: github.com/jeff-optimizely/Guiders-JS. Сейчас, о ужас, пользователям достаточно сделать клон, а лучше подключить её как субмодуль, и начать использовать.
Сделайте форк, продемонстрируйте наглядно, как должна выглядеть github-библиотека, использующая картинки, которых нет в репозитории, и чтобы её было удобно использовать. А мы поучимся.

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

Как же, вот только что про юзкейс 1 и сказали. А вот я пока не услышал ни одной объективной причины, по которой картинки нельзя хранить в репозитории, кроме это не правильно.

--depth 1 просто для информации, что так тоже можно, если есть необходимость.
Не передергивайте. Реозиторий GitHub Pages — это отдельный репозиторий от репозитория продукта, и не ломает мою концепцию. Мы же говорим о разрабатываемом продукте.
Я не собираюсь бесплатно что-то сидеть и реализовывать, еще и на своем железе. Лучше приведу пример очень известной GUI либы: github.com/richfaces/richfaces/
О ужас! Да там же ни одной картинки в репозитории (не считая showcases)! Как же они выживают, как делают все эти новмодные jQuery эффекты! КАК??!?!!?

Объективную причину специально для Вас повторю. Ресурсы проекта в виде картинок, музыки, видео, фоточек, диаграмм, тестовых данных, дампов баз, ворщитов каких то топовых менеджеров и так далее, не являются исходным кодом продукта. Как вам агрументировать факт, что не исходный код продукта не должен лежать в системе контроля версий исходного кода продукта?
Я не передергиваю. У меня действительно есть микро-проект, состоящий из 1 HTML-файла, 1 JS-скрипта, и 1 картинки (где он хостится — не важно). Всё в едином репозитории. И вы утверждаете, что этой одной картинке в репозитории не место, и её необходимо куда-то реорганизовать. На моё предложение показать пример такой реорганизации вы говорите о деньгах и железе, видимо реорганизация стоит на несколько порядков дороже, чем весь мой проект. :) Это к вопросу о категоричности ваших утверждений, и попытке распространить свою идиллию туда, где ей не место.
Если бы вы привели пример с удачным решением репозитория без картинок, это был бы лишь единичный удачный пример, не более того. Вы же утверждаете, что такой подход нужно применять всегда и везде, для доказательства этой фразы недостаточно одного примера, а вот для опровержения — вполне, и мой пример вполне годится.
Однако, даже в примере, что вы привели, есть, о ужас, бинарники!
https://github.com/richfaces/richfaces/blob/master/framework/src/main/resources/META-INF/resources/spacer.gif :)

Но с чем я безусловно соглашусь, так это с тем, что не исходники (ТЗ, скриншоты и прочее) не должны храниться в репозитории для исходников. Однако исходники это не только текст, это могут быть и картинки и другие бинарные данные, без которых проект собрать невозможно.
Я уже говорил где-то здесь, что не рассматриваю проекты в одного человека на коленке. Ради бога, творите себе в своей кухне как вам нравиться. А если хотите сообщество, извольте, что бы сообществу было удобно.
Да, конфуз вышел с richfaces, все-таки какие-то картинки там лежат. Но основные картинки в отдельных артифактах, храняться на просторах, например, мавеновских репозиториев mvnrepository.com/
Если проект не возможно без чего-то собрать, ну почему вы так уверены, что оно должно храниться в одном репозитории?
Вот берем старые джава проекты, которые еще на анте без иви. В проекте используются всякие апачевские commons-io, или гугловская гуава. И что теперь, в репо закоммитить джарники этих библиотек? Ну не собирается же без них.
Ладно, в С#, какой нибудь mysql-connector, тоже dll в репо коммитить?
Простите, что не могу привести с++ пример.
Ну раз утрированный пример вам не подходит, то покажите свой пример реорганизации тех проектов, что я приводил, чтобы обществу использовать их было так же удобно, как и git submodule add .... Ну или хотя бы смету, сколько стоит такая реорганизация. :)

А вообще, вы что-то путаете. Я не говорю, что всё обязано быть в одном репозитории (ради бога — разделяйте, если на то есть разумные причины). Я опровергаю, что в одном репо не должно быть и кода, и ресурсов. Почувствуйте разницу, так сказать. :)
Уже привел пример, приведу еще раз. Используем менеджер зависимостей. Оборачиваем картинки и другие бинарники в пакет для этого менеджера зависимостей, а в билд системе проекта указываем, какая версия пакета бинарников нужна для сборки. Прямо в текстовом файлике, который лежит с сорцами в репо. Ссылочка такая, мол взять оттуда вот такую версию пака картиночек. Сложно?

Посмотрите с другой стороны на ситуацию. Для меня всякие картиночки к нашему проекту — это 3rd party ресурс, пришедший откуда-то из других команд дизайнеров. Как и файлы локализации, и прочее в таком духе. Мое — это код. И мне в моем репозитории не нужно ничего кроме кода. Для моей работы это бесполезный хлам. Важным это все становиться в момент сборки, ибо все вместе это — продукт. И вот уже собранный продукт я могу тестировать на тестовой машине. Но в сорцах мне зачем картиночки? Ну зачем? :'(
Это всё очевидно и по сути представляет из себя нечто похожее на вынос картинок в суб-репозиторий. (Версия пакета бинарников ~= sha коммита; текстовый файл конфига ~= указатель на коммит в субмодуле). А теперь вопрос: для приведенных мной проектов это разве необходимо? Нет.

Посмотрите с другой стороны на ситуацию. Для меня всякий там код к бизнес-логике нашего проекта — это 3rd party ресурс, пришедший откуда-то из других команд программистов. Моё — это мой код ядра, над которым я работаю. И мне в моём репозитории не нужно ничего кроме. Важным это всё становится в момент сборки, ибо все вместе это — продукт.

Вывод: нужно организовывать структуру репозитория в зависимости от своих потребностей. У вас актуально разбиение по профессиям (программная часть и интерфейсная), а у меня по модулям (ядро, common-UI, бизнес-логика). И не стоит вам заставлять других использовать свой подход, равно как и другим вас — свой.
Чтож, ладно. Мне что-ли вас убеждать. Продолжайте в том-же духе :)
Только не удивляйтесь потом, почему гитхаб гайки закручивает.
Где проходит грань между исходным кодом и прочими данными? Если для запуска программы необходим конфиг-файл — он подлежит хранению в одном месте с исходниками? А если у него бинарный формат? Студия на каждую форму самовольно создаёт файл ресурсов *.resx и подключает его к проекту (не важно что в большинстве случаев его можно удалить и никто не заметит, но без него даже не скомпилится), а он бинарный — его тоже нельзя класть вместе с кодом? А что делает текстовый файлик среди исходный кодов?
Грань проходит по сфере ответственности. Кто занимается конфиг файлом и resx, программист, дизайнер, билд менеджер, менеджер, овнер?
Программист. Равно как и картинки к своей игрушке тоже рисует программист (а у него и нет никого больше в команде).
Во первых, это уже не программист, а человек-оркестр. Ну да не важно. Я сказал, по сфере ответственности, а не по ролям. Даже если дизайнер и программист одно лицо, я думаю должно быть понятно, когда ты делаешь работу программиста, а когда дизайнера (иначе это вообще печально).
P.S. Под iOS пишут на Objective-C. Это так, для кругозора.
Ресурсам не место в исходниках.
Ну здрасте. А где им место? Ресурсы ведь тоже надо версионировать.
В репозиториях, предназначенных для версионирования бинарников, а не исходников.
Ага, а потом мне писать хук на пулл, который будет запускать скрипт, который будет вытягивать картиночки и рассовывать их по нужным папочкам, иначе у меня даже файл проекта не откроется в иде.
Достаточно всего лишь использовать систему сборки и менджер зависимостей. И ради бога, не поведайте хабру, что вы храните файлы для IDE в репозитории.
Да, я храню файлы IDE в репозитории, а где ж их еще хранить? Конечно все временные файлы и прочий локальный шлак создаваемый IDE указан в .gitignore. Я даже больше скажу, я еще в репозитории и разметку UI храню, это такие xml файлики, которые руками ни кто не правит, и редактируются они исключительно в IDE, в графическом редакторе. Или мне для этого тоже отдельный репозиторий нужен? И да, менеджер зависимостей я использую для подключения сторонних библиотек, но подключать таким же образом иконки полный дибилизм.
Продолжайте себя в этом убеждать.
Файлы IDE хранить в репозитории дико и неуважительно. Вы используете одну IDE, кто-то может использовать другую. Для этого нужны системы сборки, умеющие генерировать файлы для вашей конкретной IDE. Если речь все еще о С++ — я знаю CMake, но знаю есть и другие.
Разметка UI ввиде XML файлов вполне себе исходный код проекта. Наравне со спринговыми конфигами.
Я работаю с Objective-C, тут нет систем сборки, умеющих генерировать файлы для разных IDE. По сути есть только один формат проекта который создает XCode, есть другая IDE, AppCode, на базе IDEA, она просто работает с форматом XCode, а своего не имеет, так что в этом плане у меня все ок.
Ну да. Мне что иконки к кнопкам в отдельный репо класть?
А смысл хранить бинарники под контролем версий?

А как вы представляете разработку, скажем, игры распределённой командой?
Данные ни чем не отличаются от кода. Их тоже нужно тегировать / хранить историю.

Вне контекста гитхаба.
А нечего было гитхаб как аналог дропбокса юзать. Ни разу не было необходимости хранить там файлы по 100 метров. Единственный момент где они могут появляться это игрушки. Там ресурсы вполне могут много весить.
Вот простой вопрос сколько у вас репозиториев в гитхабе? А сколько приватных?
В пору создавать свой GitHub с большими бинарниками и медиафайлами?

Думается в скором времени это мы и увидим. Потому что:
1 Очевидно, что все части проекта лучше всего хранить в одном месте.
И что нам говорит GitHub? «Для медиафайлов используйте YouTube, для всего остального DropBox»
А если я занимаюсь распознованием лиц на видео и мне нужно хранить несколько эталонных видео высокого качества.
Тоже залить все на YouTube?

2 Есть куча ситуаций, когда комерческий проект включает в себя большие файлы
Это могут быть скомпилированный проприетарные dll, различные инсталяторы, большие объемы тестовых данных.
Продукты могут включать другие продукты, и иногда, все что у вас есть — это большой бинарыный инсталятор.
Или dll+pdb. Прошли те времена, когда вы были владельцем всего вашего когда и имели исходники всех бинарников.

3 GitHub Inc. — это же комерческая компания
Как компания, которая берет деньги за тарифные планы, может запрещать что-то хранить?
Это же ужасно глупо. Ну пусть введет отдельный тарифный план для таких ситуаций, если это уж сильно им мешает.
10 центов за каждый файл больше 100мб, например.

На нужен свой гитхаб.
Жду появления YandexHub с суппортом на русском и большими медиафайлами.
Так есть же BitBucket.

Мне интересно что такое за мозгохранилище, вдруг как раз аналог gihub. А вообще мне кажется если у вас серьезный проект, вам стоит у себя развернуть gitlab, github же место для хранения исходников, а не бинарников.
У вас плохие познания в архитектуре. Бинарникам не место в SCM.
Почему? Гонять все версии всех бинарников для каждого клона, конечно, удовольствие маленькое. Но для таких целей есть mercurial с расширением «largefiles», гоняющее только хэши и нужные версии. Надо просто было добавить то же самое в git.
А еще, гитхаб и меркуриал, в отличие от svn, не позволяет выкачать только отдельную папку в репозитории. И когда в этом репозитории, из которого мне нужно получить исходный код, что бы сделать какой-нибудь фикс, лежит 100 гигабайт ненужного мне хлама в виде картинок и прочих файлов — я очень сильно огорчаюсь.
Я расписал все здесь: habrahabr.ru/post/184248/#comment_6406364

Там вы расписали что‐то не так.

Вот этот комментарий, на который я отвечаю, действительно описывает проблему. Но фикс, о котором вы говорите, надо проверить. Для этого ПО надо собрать. Для этого бинарники нужны. Если они не нужны для сборки, то их надо засунуть в другой репозиторий. Вы же не будете возражать, если рядом с этим репозиторием будет лежать другой, к примеру «static_content», с кучей бинарников? Или что фиксы надо проверять?

Это уже всё организационный вопрос. Хранить ненужные бинарники вместе с исходным кодом не нужно. Я, правда, не занимался разработкой для web и потому не могу сказать, насколько эти несколько гигабайт «хлама» могут быть нужны для тестов. Возможно, что вы огорчаетесь зря. Но если я вижу, что человек засунул скомпилированные бинарники, пачку установщиков для всех поддерживаемых систем и все снимки экрана, которые он использует на своём сайте, к исходному коду, то я тоже огорчаюсь. (Правда, таких разработчиков я ещё, к счастью, не видел.)
Исходники нужно хранить в репозиториях, предназначенных для исходного кода, а бинарники в репозиториях, предназначенных для хранения бинарников. Правильно спроектированные проекты никто не собирает локально (если это не проект, который девелопит один человек на коленке). Для этого есть два таких репозитория (например svn и nexus), система сборки проекта (например, maven), система управления зависимостями, которая для данных сорцов из svn достанет из nexus правильные бинарники (все тот-же maven), и сервер сборки (какой-нибудь jenkins). Локально собирать ничего не надо. Малый участок кода подебажить можно без сборки, а для большого дебага есть тестовый environment и удаленный дебаг.
Нарушающих эту идиллию проектов — море, но это называется legacy и подлежит реорганизации. И тут уж как поступит руководство. Но я бы не работал в конторе, в которой не движутся в правильную сторону.
Вопросы?
У вас всё-таки enterprise головного мозга. Вам человек пишет, что под web не разрабатывает, а вы «только сервер сборки, только удаленный дебаг!»
И что, что под веб не разрабатывает? Причем тут это? Т.е. сервера сборок и удаленный дебаг только для веб-проектов?
Да что-бы я хоть раз попытался запустить свою программу прямо на своем же development environment. Мне нужен чистый development environment, не с засранным реестром, файловой системой, ярлыками в меню пуск\все программы, или еще каким нибудь результатом неудачного эксперимента. Куски кода вручную можно запустить, да, но не целиком забилдить продукт и запустить его. Для этого есть тестовый environment — удаленный пул машин, локальный VBox какой-нибудь.
Потому что для не web-проектов вероятность целесообразности build-сервера намного ниже, а про удаленный debug вообще молчу. Вот зачем мне программу на iPad физически подключенному к моему ноуту компилировать на каком-то пуле машин, да ещё и удаленно! её дебажить? Однако именно это вы и предлагаете, а скорее даже категорично требуете, зачем-то перенося свой, возможно успешный, опыт на всех вокруг. Доброе утро, мир программирования гораздо шире, чем вам кажется, не стоит подгонять его весь под свои стандарты.
Да, согласен, в данном случае удаленно ничего не нужно. Но вопрос еще открыт, почему бинарники с исходники вместе? Ну собираете вы это локально, что мешает билд системе брать бинарники и сорцы с разных источников? В с++ проектах под iPad нет менеджерей зависимостей?
Зачем разбивать картинки и файлы исходного кода, если они друг с другом неразрывно связаны, и по отдельности не имеют смысла?
У меня один из текущих проектов имеет примерно такую структуру субмодулей:
Скрытый текст
image

Картинки используются в репозиториях A,L,O. Для подключения каждого из субмодулей достаточно стандартного git submodule add ...; git submodule update .... При каждом checkout необходимо иметь все эти картинки, иначе проект просто не соберется. Теперь вопрос: зачем усложнять эту структуру, вводить дополнительные репозитории, и прочее?

В индустрии ПО для iOS популярна система управления зависимостями CocoaPods, где для подключения зависимости достаточно всего одной строки pod 'LIB_NAME', и в проект подключится целиком весь код и необходимые в работе ресурсы. И никому не приходит в голову выкинуть картинки из репозитория, чтоб пользователи библиотеки мучились со сборкой. Вот типичный пример библиотечки: github.com/k06a/ABCalendarPicker/tree/master/ABCalendarPicker — картинки и код лежат рядышком и никому не мешают.

Кстати, psd-исходники из проекта A, которые занимают мегебайт 500 или и того больше, также лежат в DVСS, но в отдельном архивном репозитории, т.к. в ежедневной работе не нужны. И никаких проблем.
А что плохого, если репозиторий A станет виртуальным, а его контент разобъется на X и Y с сорцами и бинарниками? Скачали X, сорцы, поправили. Кому надо, поправит картинки в Y. Когда собираете весь проект, собираете А, и подклчаете через ваш pod 'A' и сорцы и бинарники.
Во-первых, зачем?
А во-вторых, будут сложности с синхронизацией кода и ресурсов к нему. Т.е. для ревизии кода Xn нужны картинки из ревизии Ym, однако информации о соответствии n<->m не будет ни в репозитории X, ни в репозитории Y, сами по себе эти репозитории бесполезны, их придется подключать как субмодули в родительский A. И при каждом коммите в X или в Y делать также коммит в A, чтобы сохранилось соответствие между X и Y.
Кроме того, придется искусственно дробить файловую структуру и выносить все ресурсы в отдельную директорию, тогда как порой целесообразнее иметь код и ресурсы компонента вместе.
Да, это возможно, и мне приходится делать что-то похожее, когда я вношу изменения в C или O, но просто так без причины дробить репозитории? Нет уж, спасибо.

Репозитории разделяются по принципу вероятного повторного использования.
Код из C возможно использовать отдельно? Да — тогда С — отдельный репозиторий.
Набор код + ресурсы из O возможно использовать отдельно? Да — тогда O — отдельный репозиторий.
Код из A возможно использовать отдельно от картинок? Нет — тогда никаких X и Y, A остаётся единым.

Понимаете, можно ведь и .h хранить в одном репозитории, а .c — в другом. Но зачем?
Ничего этого вам делать не придется. Для этого существуют менеджеры зависимостей. Ваш кругозор, должен заметить, очень узок и вы думаете только о репозиториях, подобных svn/git/hg. Знаете, бывают и другие. Проект X с кодом, это репозиторий git, в то время как Y репозиторий, это какой-нибудь Nexus. И в декларативном файле системы сборки, лежащем в репозитории X, четко прописано какие версии артифактов из Nexus подтягивать во время борки.
А зачем, я ответил в другом комментарии вам-же.
Угу. И от применения этого зоопарка VCS одни преимущества, и никаких накладных расходов. Прямо сказка какая-то.
Сколько команд понадобится для добавления картинки в Y, прописывания её версии в конфигурационный файл, и добавления этой информации в X?
Вместо простого
git add image.png
git commit -m '...'

А ещё, сколько понадобится команд на добавление картинки в мой репо O, и фиксации этого в L и в A, учитывая что все эти репозитории вы решили разделить?

Какой бонус от такого разделения, если например при checkout c develop на release мне всё равно нужны все картинки из Y?
Вы явно не понимаете, как это все работает. Зачем вам столько команд? Версия и артифакт объявляется только в проекте A, и все. Один единственный файлик коммититься, и бинарники беруться откуда надо.
Бинарники берутся откуда? Всегда с головы? Если нет, то тогда при изменении картинки, мне надо обновить версию репа с бинарниками, потом пройтись по всем остальным репам с кодом, и подправить конфиги, что бы те указывали на новый тег бинарного репа, что бы менеджер зависимостей все правильно собирал.
О, у вас программисты картиночки обновляют? Скажите, может вы их еще сами и рисуете? Вам хоть доплачивают?

Тем временем в нормальных условиях работы приходит реквест от дизайнеров, что обновился графический пак. Билд менеджер открывает один единственный конфигурационный файл в репозитории сорцов, меняет там версию, коммитит изменение, и вуаля — следующий билд продукта с новыми картиночками. Заметьте, разработчик в процессе даже не участвовал.
А если я занимаюсь распознованием лиц на видео и мне нужно хранить несколько эталонных видео высокого качества.

Простите, а зачем пихать образцы входных данных в исходные коды софта??? Сделайте как сказано — поместите в Dropbox или на своём сервере, других службах аналогичных. В конце-концов вы эти самые видео высокого качества будете поставлять со своей программой потребителю?
Пошёл удалять комментарии и переносы строк
То есть у вас есть исходник в 100 мб?
Исходники не большие, но вот комментарии и переносы строк…
Как вариант, нейронная сеть может весить больше, чем 100 МБ. Её то уместно хранить в репозитории?
GitHub — это сервис для хранения исходного кода, а не тяжеловестных ресурсов. На вашем месте я бы залил ее куда-то на GDrive
Проблема в том, что разработчик, пишущий какое-нибудь open-source приложение, не имеет возможности его распространять через гитхаб, потому что гитхаб не предоставляет никакого репозитория артефактов. Т.е. если я имею репозиторий на гитхабе, то мои пользователи либо обречены сами собирать его из исходников, либо я должен создавать сайт продукта, чтобы там распространять готовое приложение (а возможно мне требуется хранить несколько версий приложения для скачивания).
Именно поэтому я для себя выбрал bitbucket, т.к. там я могу хранить не только код, но и документацию (вики), и багтрекер, и готовые сборки для пользователей.
Битбакет хорош, но, справедливости ради, на гитхабе тоже есть и вики, и багтрекер. А бинарники можно хранить на bintray.com/ или sourceforge.net/
Согласен, но пользоваться чем-то одним всё-таки удобнее. Да и ограничений на приватные бесплатные репозитории (даже командные) у битбакета меньше, чем у гитхаба. При этом вам доступен и Git (как на гитхабе), и mercurial, что тоже меньше ограничивает свободу разработчика.
А гитхаб дает svn-доступ, для меня это киллер фича. С дистрибуцией продукта сложнее, да, но гитхаб никогда и не рвался решать подобные проблемы. В конце концов, если это какой-то фрэймворк или либа, то положить ее в популярные серверы зависимостей и все. А если opensource проект более менее развит и известен, как у него может не быть веб-сайта?
Считаю, что решение правильное, потому что исходный код — это исходный код, и хранить медиафайлы или бинарики такого размера — значит не понимать вообще принципа git.
Для хостинга и версионирования файлов есть огромное количество решений сторонних, тот же дропбокс — храните хоть картинки, хоть видео, хоть что угодно, версии за последний месяц сохраняются.
Что касается самих исходников, гитхаб — отличный инструмент, который ЛОГИЧНО развивается. Можно и скрипкой гвозди заколачивать, но она не для этого.

P.S. те, кого не устраивает решение гитхаба по этому поводу — посмотрите в сторону bitbucket, там вроде пока таких проблем нет(сами пользуемся), инструмент ничем не хуже. Но все же, может это не спроста? Может это просто ЗНАК чтобы пересмотреть архитектуру своих проектов? Я бы на месте возмущенцев, отнесся именно так.
С моей точки зрения это выглядит как проблема в архитектуре git. Мы не можем создать аналог largefiles — мы запретим большие файлы вообще. Выше уже приводили множество примеров, когда большие файлы нужны, причём хорошо бы именно в репозитории (случаев, когда большие файлы в репозитории необходимы ещё не приводили). Я лично никогда бы не стал по собственной инициативе помещать большие бинарные файлы под контроль git (именно git). Но только потому, что у git нет largefiles, а я не хочу ждать лишние минуты, пока бинарники для ненужных версий загружаются, а не потому что я противник помещения больших бинарных файлов под контроль СКВ вообще.
Как я написал выше, largefiles большущий костыль. А тем, кто выступает, что «хорошо бы», пора учить матчасть и не позориться. Если что-то для кого-то хорошо и удобненько, это еще не значит, что это правильненько и не содержит архитектурных ошибочек. И не является лишним растрачиванием ресурсов.
Меня несколько удивляет позиция тех, кто одобряет такое решение. Ведь для конечных пользователей никаких плюсов нет, это исключительно оптимизация затрат самого Github, так о каком «правильно сделали» идет речь, если смотреть на ситуацию прагматично, вам же от этого ничего не прибавилось? Мне вот, по большому счету, безразлично, поскольку с необходимостью хранить такие большие файлы я не сталкивался, и вряд ли столкнусь. С другой стороны, ситуации всякие бывают, поэтому легкое беспокойство все-таки есть. И осуждать тех, кто хранил в репозитории большие pdf'ки или бинарники, просто потому, что это удобно, я не собираюсь. Ну и что, что они для этого не совсем предназначены? Далеко не все и не всегда используется именно так, как задумано, и если результат оправдывает средства, идеология идет лесом.
А сам факт закручивания гаек может означать начало политики по оптимизации затрат, которая может далеко завести. Github уже очень многих подсадил на себя и вполне может начать извлекать из этого прибыль. И вот эта мысль мне уже не нравится.
А мне нравится другая мысль, что я больше не нарвусь случайно на репозиторий на гитхабе, в котором лежит нужный мне код, и в придачу не нужные мне ресурсы весом более 100 мегабайт. Да я просто счастлив. Я не вижу, чем тут результат оправдывает стредства, я вижу невежество в познаниях. Кроме «удобно что все вот тут в одной папочке лежит» я больше не увидел веских доводов, что так нужно делать.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации