
Почему я не отправляю сгенерированные файлы в репозиторий?
- 12 ноября 2015
- 5 мин
- 3 175
Это перевод статьи Кента Додса «Why I don’t commit generated files to master».
Этот вопрос давно является предметом для дискуссий. Каждая сторона приводит свои доводы за и против этого подхода. В этой статье я расскажу вам о своём опыте работы с коммитом сгенерированных (созданных) файлов в репозиторий для моих библиотек и о том, почему я этого больше не делаю.
Что такое «сгенерированные файлы»?
В контексте библиотеки, сгенерированные файлы — это собранные, скомпилированные и минифицированные версии, которые пользователь подключает на свою страницу, например через <script>
.
Для библиотеки из одного файла сборка не нужна, но для работы модульной библиотеки в старых браузерах, без поддержки модулей ES6, необходимо эти модули собрать в один файл. Такую сборку я и называю «генерацией файлов».
Зачем нужна сборка?
Вы возможно испытываете искушение сделать коммит созданных файлов в репозиторий по нескольким причинам:
- Они необходимы для bower (перестаньте использовать bower).
- Это проще для людей, которые хотят просто скачать файлы и не используют пакетные менеджеры типа npm или bower.
- Используя rawgit, собранные файлы можно легко подключить напрямую из репозитория библиотеки на GitHub в свой проект или в демонстрации на jsbin или plunker.
Довольно долго я тоже коммитил свои снегенированные файлы в репозиторий библиотек, и это работало отлично! Пока я не столкнулся с проблемами.
Проблемы
Вот несколько проблем.
Обманчивые скачки изменений кода в статистике

Выглядит как большое количество новых изменений, не так ли? Нет! Этот скачок произошёл, когда сборка была добавлена в ng-stats (было и несколько других существенных изменений). Последующие скачки происходили всякий раз, когда выпускалась новая версия (и следовательно, повторная сборка заново коммитилась). Становится сложно понять, сколько кода изменилось на самом деле в проекте.
Ужасный git diff

При разработке библиотеки нужно убедиться, что коммит сгенерированных файлов делается только при выпуске релиза (но не при других изменениях файлов), в противном случае будет намного сложнее определить в git diff (утилита для просмотра отличия в коде между коммитами), когда и какие изменения были внесены в код.
Но даже при коммите собранных файлов только при выпуске версии diff двух коммитов, разделённых сборкой, превращается в кошмар.
Сложность совместной разработки
Для open source кода важно обеспечить лёгкость совместной разработки и привлечения новых программистов. Я часто получал пулреквесты, с изменениями в сгенерированных файлах, а не в исходных — и эти изменения будут перезаписаны при следующем запуске сборки! В других пулреквестах в код включены собранные файлы, из-за чего сделать ревью кода значительно сложнее (смотрите пункт «Ужасный git diff»).
Для таких пулреквестов мне всегда приходилось (дружелюбно) просить участников переделать пулреквест, чтобы этот коммит не попал в мою историю. Это не самый хороший опыт для контрибьюторов.
Если вы хотите, чтобы люди вносили вклад в вашу библиотеку, вы должны сделать это настолько просто, насколько это возможно. По моему опыту, это намного проще осуществить, не храня сгенерированные файлы в репозитории.
Моё решение
Можно хранить собранные файлы в репозитории без вышеперечисленных недостатков. Для этого отправляйте сгенерированные файлы в специальную ветку. Я называю такую ветку «latest», и автоматизирую этот процесс с помощью пакета publish-latest.
Вы запускаете сборку вашей библиотеки, затем пакет publish-latest. С помощью скрипта, он создаёт коммит из сгенерированных файлов и добавляет его в ветку latest. Запускать publish-latest можно и локально, но будет лучше использовать semantic-release и TravisCI (или любой другой CI-сервис) для подготовки релизов вашей библиотеки.
Преимущества моего метода
- Для bower отметьте тегом коммит, сделанный при помощи publish-release (semantic-release делает это за вас).
- Для прямого скачивания сгенерированных файлов используйте созданную ветку «latest».
- Для rawgit тоже укажите ветку «latest».
Как этот метод решает проблемы?
- Большие скачки изменений в гите — просто игнорируйте ветку latest, сфокусируйтесь на master (с помощью графика изменений от контрибьюторов в GitHub).
- Огромные git diffs — вам никогда не понадобится git diff на ветке «latest». Это просто сгенерированный (бесполезный для гита) код.
- Пулреквесты в ваш код — напишите в руководстве по внесению изменений (Contributing.md), что ветка latest только для хранения сборок и пулреквест следует делать от других веток.
В качестве примера работы с publish-latest посмотрите мои репозитории и проекты других людей.
Заключение
Существует множество инструментов, которые помогут вам в развитии ваших open source библиотек.
Мои примеры на Egghead.io демонстрируют процесс с самых азов до строительства большой библиотеки. Я рекомендую вам к просмотру статью «Как писать JavaScript библиотеку с открытым исходным кодом».
FAQ
- Работает этот метод с CDNJS? С angular-formly — очень хорошо.
- Как насчёт того, чтобы хранить ветку latest в отдельном репозитории? Это, кстати, неплохая идея. Используя флаг url в publish-latest, вы сможете легко это сделать.
Похожие статьи
Шпаргалка по Git. Решение основных проблем
Перевод «First Aid Git» от команды HTML Academy
9 полезных плагинов VS Code для вёрстки
Собрали подборку плагинов, которые ускорят работу и сделают всё красивеньким.
Полезные команды в консоли Windows
cd, rd, md, help и другие способы ускорить работу в консоли.