Pull to refresh

Comments 299

Что-то в этой истории притянуто за уши.

Если бы Facebook планировал сам работать над улучшением производительности git, то ему не нужно было согласие его мантейнеров. Он мог бы просто взять и сделать.

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

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

А причем тут лицензия на код? Скорее всего дело вот в этом:

Кстати, мы наняли автора Mercurial.

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

в теории, да. На практике гит — это небольшой проект на 600 файлов кода с тремястами коммитами за последний месяц. Поддерживать такой форм можно в одно лицо вполне свободно. Если раскидать на команду, то вообще незаметно будет.

А представляете какая обуза мейнтейнеру поддерживать чужой код, который был добавлен только потому, что Файсбуковцы опять не осилили декомпозицию?

Все стремятся к монорепам, а вы про декомпозицию...

Огребают кучу проблем, созревают на этом и в конце концов разделяют репозиторий?

Или переходят на нормальные CVS

Обратно - огребли кучу проблем с микрорепами и собирают всё в один.

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

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

Ветки можно создавать в любом репозитории: и в моно-, и в поли-. Вот только в полирепе это будет N веток по числу реп, с которыми приходится работать. Не понял ваш комментарий про "ничего лишнего не прилетело". В системе контроля версий вы всегда сами выбираете, какую ревизию счекаутить. Если вы имеете в виду процесс синхронизации долгоживущей ветки с основной, то в полирепе у вас будут те же самые проблемы с мердж-конфликтами. Рано или поздно все ветки придется вмерджить в master/trunk/main etc.
После того, как все изменения закоммичены в ветки, все это добро нужно будет отправить на CI и code review. И тут снова вместо одного пулл-реквеста у вас будет N пулл-реквестов. Внутри CI ваш код будет запускаться с другими версиями соседних репозиториев, т.к. в соседних репозиториях пулл-реквесты еще не вмерджены в основную ветку. Соответственно, в разработке это придется учитывать, какие-нибудь флаги и условия расставить. Либо просто забить на CI и мерджить как есть.

Вот только в полирепе это будет N веток по числу реп

Поцчему?
Вот например у нас форк memcached и N проектов.
Создали ветку в репе memcached и все.
А у Вас как-будто N монореп

Изначально речь шла об организации кода, разрабатываемого внутри компании - хранить ли его в одном большом монорепозитории или в множестве маленьких - полирепозитории. Мой пример относился к сценарию, когда нужно внести изменения в несколько разных частей в кодовой базы - библиотеки, микросервисы, какие-то тулы и т.п. Допустим, мне в рамках работы над проектом надо внести изменения в код 1 сервиса и 2 библиотек, от которых сервис зависит. Если все это хранится в разных репозиториях, то нужно сделать 3 пулл-реквеста. Разве не так? В монорепозитории я могу обойтись 1 пулл-реквестом. В фейсбучной монорепе, о которой пишется в статье, это мог бы быть стек коммитов (диффов), связанных с друг другом. Такой стек можно к примеру поребейзить относительно более свежей ревизии монорепозитория одной командой. В полирепозитории в каждом подрепозитории ребейз (или мердж) нужно делать отдельно.

Мухи отдельно, котлеты отдельно.
Хотя я хз, как код Windows организован. Хотя он и не сайт.
О, а сколько в таком случае тесты выполняются?
А так я вообще не использую git, когда хочу, а правлю сразу по ftp, тоже удобно.
И удобно файлы по ftp перекидать с одного сайта на другой. Не нужно ничего коммитить и т.п.

Я очень далек от монореп, но как будет сделано в монорепе при независимом развитии? Вот мы ведем 2 параллельных проекта, каждый наверное в своей ветке.
В рамках одного проекта потрогали свой сервис и пару библиотек, ребята из параллельного тоже потрогали эти библиотеки, хотят зарелизиться, но не могут, так как у нас конфликт по библиотекам, а так как мы можем выложиться только пачкой 2 библиотеки и сервис, то ветка долгоживущая, значит конфликтов будет много. Переход на версию +1 библиотеки 1 тянет за собой переход на версию +5 библиотеки 2, так как обе версии выложены одним коммитом. Кажется мозг взорвется раньше на монорепе, чем на куче отдельных.
В отдельных ты можешь спокойно в своем мастере пилить свой сервис, поднимать версию одной библиотеки независимо, когда сам захочешь, вливать свои изменения во все связанные библиотеки маленькими кусочками, а не толпа сервис+сразу обе библиотеки, коллеги, обновляйте обе синхронно.

Переход на версию +1 библиотеки 1 тянет за собой переход на версию +5 библиотеки 2, так как обе версии выложены одним коммитом.

Предполагаю, будет в этом случае сделаны рядом libmoo3 и libmoo4, и разные проекты будут тянуть за собой разные версии, указанные явно :)

Форк такого рода в Git достаточно дешёвый. Главное, чтобы старая версия не сохранялась ещё надцать лет после того, как удалён последний использовавший её проект.

Cложности в таком сценарии вызваны не способом хранения кода, а тем, что 2 проекта долгое время живут независимо друг от друга, код в них сильно расходится, что приводит к большому числу конфликтов. Если оба проекта в итоге будут мержить свой код в основную ветку, то конфликтов не избежать в любом случае, независимо от способа организации кода. Полирепа лишь позволит в каких-то репозиториях этот процесс немного отложить за счет технического долга.
Одно из возможных решений тут - не заводить долгоживущих веток. Примерно так:
1. Вливать изменения в основную ветку как можно чаще: дробить коммиты, не накапливать тысячи строк изменений. Бонус - небольшие пулл-реквесты проще ревьювить.
2. Нужен CI, который соберет код и в идеале еще запустит тесты и позволит убедиться, что сервисы во втором проекте не ломаются от изменений в первом. Наличие такого CI дополнительно мотивирует выкладывать код в основную ветку чаще.
3. При необходимости стоит прятать новые фичи под флаги. В качестве бонуса эти флаги потом в A/B тестах можно использовать.
4. Релизить сервисы чаще, не копить изменения месяцами/годами.
Проблему разрешения конфликтов в коде все эти меры не решают, но позволяют уменьшить число конфликтов, цену ошибки и т.д.

Переход на версию +1 библиотеки 1 тянет за собой переход на версию +5 библиотеки 2

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

Причём тот же Microsoft вполне себе запиливал улучшения для здоровенных монореп.

В 2017, в апстрим в году 2021 взяли

ну так фейсбук 5 лет ждать не мог

Если не ошибаюсь, то в районе 2015 года MS окончательно полегли под своими доморощенными решениями, доисторическим кодом и полным бардаком в управлении разработкой. В результате чего приняли долгосрочную программу по улучшению работы со своей внутренней инфраструктурой. Там было всё - облака мечты, хранилища данных мечты, пайплайны мечты и т.п. И всё с уловием, чтобы не менять разработчиков и процесс разработки. Если не ошибаюсь называлось оно "1ES" и "Cloud пафосное чего-то там".
Одним из основных пунктов программы было улучшение поддержки огромных репозиториев утилитами контроля версий, чтобы сохранить монорепу и устоявшиеся подходы к разработке внутри имеющихся команд разработчиков (когда индус, которого лично никто никогда в глаза не видел, на личном ноутбуке компилирует всю Windows XX в попытках добавить новую кнопку в MS Paint).
И это была многолетняя (на пять лет минимум) серьёзная программа с этапами изучения своих потребностей, изучения возможностей git, изучением возможности сохранения совместимости и т.п. С понимаем, что именно нужно получить, чтобы перевести разработку из состояния ада в страну розовых пони. С формальным описанием того, как именно они видят разработку своей мечты и пониманием, сколько именно хрентелионов долларов это всё на выходе сэкономит и во сколько раз уменьшит интервалы между выпусками новых версий Paint и кнопок "Пуск".
То есть со стороны менджемента и финансов поддержка программы была абсолютной - кнопок "Пуск" никогда не бывает мало, а инвесторы очень любят эффективные инвест-программы и маячащие впереди хрентилионы долларов экономии. И это важно, так как позволило реально бросить невероятные ресурсы на решение задачи, финансировать всё это в течение многих лет, сравнить результаты с запросами и рассказать инвесторам, какие все в менеджменте молодцы (а если менеджмент счастлив, то и программистам никто работать не мешает).

В начале 2017 у них уже был GVFS (VFS for Git), который является ключевой фичей для поддержки огромных репозиториев. В середине 2017 GitHub объявил о поддержке GVFS, т.е. проект уже однозначно был в стадии продакшина. Судя по всему, это была попытка запилить свой собственный Git. С интересными и уникальными плюшками и почти совместимый. И таким образом попытаться переключить весь мир на свое поделие и дальше уже творить с ним всякое. Всё как MS любит (привет Java, JS, HTML и многому другому).

К 2021 году в MS осознали, что у имеющегося Git слишком большая инерция, от которой при попытке задавить основную ветку даже у них пупок надорвётся. Тем более, что конкуренты только и ждут повода испортить намечающийся праздник (у Google и прочих были точно такие же проблемы и различные наборы костылей для их решения). И тогда родился "Scalar", который был объявлен колоссальной доработкой глубинных потрохов основного Git на основе имеющихся наработок GVFS.
Возможно я не прав, и GVFS действительно был площадкой для обкатки технологий с прицелом последующего слияния с основным Git, но жизненный опыт и чуйка говорят, что в случае MS так не бывает - там всегда будет попытка подмять продукт под себя.
Судя по тому, что на данный момент scalar вместе со всеми сопутствующими костылями (git maintenance и т.п.) является частью основного Git ("git scalar"), то всё получилось - MS превратили git в VCS своей мечты. Правда он остался независимым и цельным, но это небольшая потеря - хрентилионы долларов экономятся, а индусы улыбаются во сне.

Что мешало Facebook поступить так же:
- изучить задачу и ограничения Git;
- форкнуться, сделать собственный вариант для использования внутри компании, куда добавлять плюшки, убеждаясь, что остаётся совместимость по workflow, командам и утилитам с основной веткой;
- в процессе тыкать носом разработчиков git во все найденные косяки и проблемы, пока абсолютно все не признают ущербность текущей архитектуры и то, что разработка основной ветки на полном ходу идёт в тупик;
- обкатать всё внутри себя и выработать реальный workflow под новые плюшки, заодно вылизав продукт до блеска под собственные нужды
- подкупом, шантажом и вымогательством продавить слияние с основной веткой. В качестве козырей размахивать найденными косяками и тем, что все вносимые изменения совершенно точно ничего не ломают.
- profit

Из принципиального преимущества у MS был GitHub, на котором они смогли обкатать изменения не только внутри компании, но и в 100500 сценариях использования на 100500 пользователях. И в конце разработки достать убойный козырь "наши изменения гарантированно ничего не ломают в Git, так как они уже внесены в GitHub и там всё у всех работает". Обвинить GitHub в некошерности духу не хватило ни у кого. Тем более, что всё и правда работало, ничему не мешало и ничего не ломало.

Более того, судя по дате покупки GitHub и тому, как всё развивалось, покупка GitHub была именно частью плана по допиливанию Git под свои нужны и созданию инфраструктуры мечты. Которая совершенно полностью оправдалась и окупилась, и даже прибыль приносит. На этом монстре и его зоопарке пользователей, включая монстрический энтерпрайз, были обкатаны и отполированы до зеркального блеска все необходимые для MS такие же монстрические изменения.
Короче, в кои-то веки MS использовали свой статус мега-корпорации во благо. Возможно, что случайно. Возможно, что хотели как всегда, но инерция сообщества вынудила сделать хорошо. Но, тем не менее, пока всё так - все счастиливы, прибыли растут, git получил огромный толчок к развитию.

Почему FB не поступил как-то примерно так же, неясно. Они упёрлись в принципиальную проблему, которая ограничивали их рост и вела к убыткам, и даже в изучение проблемы не вложились толком.
Просто слали разработчиками Git жалобы о том, как там внутри всё плохо и грустно и какие-то отдельные разрозненные предложения без общего видения картины и объяснения перспектив. И обижались, когда их посылали. Ну, так в любом open-source внутри вовсе не розы, а вонючее легаси из гаражных hobby-проектов, а разработчики бородаты, токсичны и упёрты.
Но вы же IT мега-корпорация или кто?
Вложитесь, изучите, рассмотрите варианты возможных решений, которые принесут вам ещё +100 прибыли. Посчитайте, и если окажется, что вам это выгодно, то используйте всю свою корпоративную мощь - пилите, доморощенные версии, обкатывайте, покупайте публичные сервисы, несите в массы, обкатывайте там, доказывайте, что оно лучше, работает, не имеет побочек и потом бросайте ресурсы, чтобы продавить это всё в основную ветку.
Тем более, что на этапе "покупайте публичные сервисы и несите в массы", к вам присоединятся примерно все корпоративные монстры, включая лютых конкурентов. Так как у них у всех аналогичные проблемы, а вы тут вбрасываете решение и даже ничего взамен не просите. Тут при правильном подходе вам и оттестируют и пилить помогут, и разработчиков основной ветки продавят. И будут вам тёмной ночью разработчики Google с персональных аккаунтов офигенные патчи слать.

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

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

Наверное потому что им надо было уже в 2012 что-то разрабатывать,а не ждать 5 лет, пока смогут запилить нужные вещи.

Опять же сравните размеры компаний - даже сейчас это не очень сопоставимые компании, а в 2012 году Цукерберг только вышел на публичное IPO, с надежной получить 5 млрд инвестиций на развитие. Для MS 5 млрд уже тогда были карманными расходами.

В целом наверное так. Но в 2017 у MS уже был готовый для продакшена git со всеми необходимыми плюшками. Потом ещё два-три года они пытались пересадить на него весь мир, пока не поняли, что это гиблое дело и нужно сливаться с основной веткой.

То есть разработка гита свой мечты заняла у них 2 года.

И ещё до года заняла интеграция с GitHub (но тут огни его купили и большую часть интеграции пилила сама команда авторов GitHub).

Слияние с основной веткой заняло от года до двух.

Думаю, данное решение во многом дело случая. Плюс ситуации разные. Одно дело: компания с большой историей довела разработку "до ручки" и бросила все силы на решение проблемы, а другое - достаточно молодая компания выбирает для себя оптимальное решение. Причем не сказать, что Mercurial - noname, хотя да, в тени Git.
Еще интересно, что статья про Git и Microsoft появилась достаточно недавно https://habr.com/ru/articles/795635/ Прямо цикл)

>Почему FB не поступил как-то примерно так же, неясно

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

Это тот же Фейсбук, который примерно в ту же пору хотел в ядро андроида протолкнуть коммит с повышением лимита на количество созданных объектов, чтобы не надо было оптимизировать своё откровенно дурацкое приложение

Погодите.
Пришла такая Мета к Гиту и говорит: мы тут накрутили огромную репу и она тормозит. Срочно починитесь.
На что гит, как и положено опенсорсному проекту сказал типа "вам надо - вы и чините". Можете прислать PR. А пока PR нет - можете разбить репозиторий и всё будет работать. Т.е. не просто послали, а предложили вариант решения проблемы.
Мета обиделась и пошла к умирающему меркуриалу, у которого 2% рынка VCS. Те от такой великой чести прогнулись и решили сами бесплатно всё запилить.
Почему Мета не могла помочь сообществую и запилить фичу своими силами - не понятно.

Не похоже. Скорее, они сказали, давайте, мы переделаем гит под гигантские монорепы. А те им сказали, это в архитектуру не вписывается, вы б ещё дум туда встроили. Используйте гит правильно и будет вам счастье. Ну а в фейсбуке подумали, да ну ещё разбираться, правильно использовать, и пошли к меркуриалу, которому деваться было некуда.

Это, кстати, действительно, более вероятный сценарий. Типа, не надо встривать ваши извращения в нашу архитектуру.

И в итоге всё-равно встроили, только от мс.
Интересно было бы узнать что сейчас об этой ситуации думают ментейнеры гита, которые тогда отвечали в духе "вы не должны этого хотеть".

Ну, справедливости ради, там не просто встроили. Там MS очень сильно причесали и переписали потроха Git с сохранением совместимости.
Вот, что сказали разработчик git...
Возможно их подкупили улучшением общей архитектуры проекта.
Но и в целом, там ситуация непростая была. У MS это всё уже продуктово работало на их собственном клоне Git на GitHub. И крупным корпоративным клиентам результат очень понравился, а не нравилось только то, что это принадлежало MS.
Так что разработчики git были однозначно "неправы" и в какой-то момент оказались перед лицом возможной жёсткой конфронтации к GitHub со всей его клиентской базой, за которым стоял MS со всеми своими ресурсами и деньгами, и при этом ещё и с поддержкой корпоративных клиентов. В "Git против GitHub" это "пчёлы против мёда".
Честно говоря, при таких раскладах у мейнстрима Git просто не было выбора - они фактически пытались идти против требований рынка и сообщества. В конце концов их бы задавили, сделав "в складчину" какой-нибудь некоммерческий клон Git под крылом какой-нибудь новосозданной некоммерческой организации. И всё сообщество дружно бы пересело на новый git. Через два-три года всё было бы кончено. Но результат был бы хуже, чем сейчас, так как в процессе созданий этой некоммерческой организации однозначно случились бы корпоративные войны, которые сильно повлияли бы на результат. Например, есть уверенность, что в Google в какой-то момент подключился бы к процессу и попытался продавить какие-то свои собственные решения в пику MS.
Ну, и сами мейнтейнеры, тоже где-то работают и оказать в оппозиции со своим работодателем и вообще с большинством крупных работодателей, тоже такое себе удовольствие. Можно же и новых мейнтейнеров обучить и пропихнуть.
Но и MS понимали, что если не отдадут всё в безусловный опенсорс, то погрязнут в корпоративных войнах. А у них же GitHub свежекупленный есть, который прибыль должен приносить. И инвесторы не поймут. Да и "ехать" им было тут выгоднее чем "шашечки".

Это понятно.
Больше интересно как бы всё случилось, если бы те ментейнеры, заворачивающие призывы от фейсбука смогли тогда ещё предвидеть подобное развитие ситуации.
В тот момент времени им не хватило прозорливости чтобы осознать развивающуюся потребность, которая рано или поздно приведёт к изменениям и поддержке больших монореп.
Но будь они дальновиднее, вошли ли бы они в диалог и в развитие этой функциональности, или мешало что-то ещё кроме непонимания потребности.

Причем, я работал с SVN лет 15 назад и там подход с тем, что в каждом каталоге создаётся подкаталог .SVN давал больше проблем, чем плюсов, думаю, что FB* такие пришли и начали "ломать" архитектуру и принципы гита после чего были благополучно посланны. Ну я бы послал бы, правда, потом бы мог прийти менеджер и объяснить, что это сотрудничество очень важно для нас, но и у него был бы шаг быть посланным.

Ну я представлю себе ситуацию, когда приходит разраб новый на проект и ему говорят, мол, для начала надо поправить функцию, которая вощвращает список стикеров, но для этого надо скачать на комп ВЕСЬ FB*, это сколько? 100 гигов? 500? Потом поправить и для тестирования локально запустить? Это ни одна IDE не сможет вытянуть? О какой подсветке синтаксиса и выводе списка методов можно говорить на таком проекте?

Ну т.е. это прям антипаттерн проектирования и под него необходимо переделать гит, т.е. где-то в нормальных кецсах он станет работать хуже? А оно надо?

Потом поправить и для тестирования локально запустить?

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

Я тут недавно репо с гитхаба пытался скачать. Там всего-ничего 9 гигабайт было. Но zip-файл, который можно скачать докачку не поддерживает, через git-клиента стащить удалось только раза с 6, постоянно дисконнекты (а git-клиент докачку тоже не умеет)

и все это счастье с depth 1?

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

а git-клиент докачку тоже не умеет навер

Умеет. Вы, наверно, git clone запускали. Потому что если сделать init + fetch, то докачка работает с момента обрыва. Не идеально, некоторые мета-части передаются заново, но есть сохранение принятого.

Ну и ещё есть https://github.com/johnzeng/ResumableGitClone и наверняка ещё десяток похожих проектов.

Интересные варианты, надо будет при случае попробовать. Когда я гуглил как бы стащить большой репозиторий, гугл мне не помог и такие варианты не предлагал (ну или я гуглить разучился)

А Майкрософт в итоге сделал для себя эти ускорения и залил в апстрим

Ну да, передумали в гите. Может майкрософт был убедительнее, потому что у него гитхаб. А может гитовцы просто посмотрели вокруг и решили принять реальность, где у больших фирм есть большие монорепы.

Или может MS просто не сломали всю архитектуру к черту, а встроили свою фичу как надо. Не могу сказать что это в духе MS, но чем черт не шутит.

Согласной этой статье, по состоянию на 2017 год они все свои наработки опубликовали в open-source, но пока не смогли пропихнуть в апстрим. Так что, у них свой клиент, свой сервер, но по протоколу полностью совместимый (т.е. можно линуксовым git-ом забирать из TFS-репозитория и наоборот, из VisualStudio-клиента пушить на гитхаб).

Недавно была новость, что основные фичи, не ломающие совместимость, пропихнули. И там очень много крутого. Причём им пришлось все потроха гита перетряхнуть и полностью переписать его внутренний VFS ради того, чтобы совместимость не потерять. Но на выходе и совместимость и плюшки для МS с поддержкой тербайтовых ропозиториев. И есть задел на ещё больше плюшек.

Давно уже есть, git scalar, git maintenance и прочее

Ну как давно, с 2021. До этого был gvfs

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

Почему Мета не могла помочь сообществую и запилить фичу своими силами - не понятно.

Наверное, из принципа взаимности:

На что гит, как и положено опенсорсному проекту сказал типа "вам надо - вы и чините"

И фейсбукерши...

Фейсбуковки жеж!

Официально: "Metamates".

Честно – не слышал ни одного некринжового "названия сотрудников компании", включая компании, в которых работал. Metamates, пожалуй, одно из более приятных, но всё равно кринж.

В сегодняшних реалиях наверное уже метамордо...

Особенно, учитывая, что mating — это спаривание по-русски.

а git - вообще "мерзавец"

Да и по английски как бы тоже

Т.е. метовые?

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

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

Если проследить историю гитхаба, то можно найти какая очередь стояла на покупку гита. Я думаю FB не смог купить (чк посчитал что слишком дорого за опенсорс)…итого купили майки. Конец интересной истории

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

Как какая? Первые три буквы одинаковые!

А знаете у кого еще первые три буквы такие же?

Обожаю mercurial. Одни бранчи чего стоят! И честно говоря не понимаю, что хорошего в git.

что хорошего в git.

github/gitlab со своими плюшками.

Это совсем не git.

Хочется плюшек - учите git. Со своим mercurial на github не ходють ;)

А hg git на что? Все нормально зодится. Да и в меркуриале и без того плюшек дрстаточно. Более того, они уже были, а гита еще не было.

Да и в меркуриале и без того плюшек дрстаточно. Более того, они уже были, а гита еще не было.

Ну зачем же так, всё проверяется:

Git: Initial release 7 April 2005

Mercurial: Initial release 19 April 2005

Стиль Github, GitLab, Bitbucket - это "разрешим работать с распределённой VCS ко ак с централизованной". Это не родное для Git.

Более адекватное приспособление к стилю собственно Git это Gerrit. Он используется как серверная база в самом гугле (с сильными внутренними подточками). Но у него нету CI и прочих удобств в едином флаконе, их надо довинчивать.

Популярность - git это стандарт де-факто. Я лично очень сильно огорчился, когда пришлось уйти с mercurial на git, но выбора особого не было: меркуриал я мог использовать только в личных проектах, да и там приходилось городить синхронизацию с git ради GitHub, а во всех совместных и рабочих проектах был git и никаких шансов убедить всех коллег мигрировать на меркуриал. В результате отказ от меркуриал сделал жизнь заметно проще.

А какие такие проблемы с бранчами git-а? Можете пояснить?

Их отсутствие. В гите есть только указатели на коммиты. А бранчи все выдумывают пре-коммит хуками кто во что горазд. Я уж не говорю о том, что он каждый коммит хранит целым снепшотом состояния репозитория, а не просто диффом изменённых файлов, от чего при переименовывании файлов ему приходится угадывать что откуда пришло и часто не справляется, а для отображения диффа и мёржа ему приходится опять же угадывать, где какие были изменения сравнивая разные снепшоты.

Кто хранит каждый коммит целым снепшотом?..

Таки гит хранит, судя по интернетам. Удивлён =)

После CVS/SVN/SCCS я считаю что хранить каждый файл не диффом а целиком это здравая идея, и переключение между бренчами происходит гораздо быстрее. И вообще создание бренчей - легкий и быстрый процесс. Но да, раньше мог сильно тормозить если у вас сотни тысяч файлов в репозитории

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

Но то, что с папками и переименованиями беда конечно факт.

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

В гите есть только указатели на коммиты. А бранчи все выдумывают пре-коммит хуками кто во что горазд.

Вы тут "бранчами" называете теги сообщения коммита, которые показывают, в рамках какой разработки был сделан коммит. Ни в Git ни, на самом деле, в Hg это не нужно, если есть возможность писать его в сообщении коммита - что всегда и делается в процессе уровня больше чем "я и моя собака".

Как сами меркуриаловцы признают, "The term branch is sometimes used for slightly different concepts. This may be confusing for new users of Mercurial." В результате получаются ситуации типа "Две ветки-2 в пределах ветки-1 (не путать с веткой-3)" (ветка-1 это его внутренний branch, ветка-2 это безымянная голова, ветка-3 это bookmark).

Я уж не говорю о том, что он каждыйпо коммит хранит целым снепшотом состояния репозитория, а не просто диффом изменённых файлов

А это _в основе_ единственно правильный вариант (ну не учитываем, что объекты могут представляться в виде дельт, это уже вопрос сжатия репы). Трекинг копирования/переименования должен делаться уже отдельно поверх него.

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

Для сложных случаев типа "переместили 200000 файлов и при этом изменением `#include <moo/foo/boo/boo.h>` на `#include <util/moo/foo/boo/boo.h>` поменяли их хэши... ну да, можно было бы придумать какие-то подпорки. Но, насколько видим, это даже для крупных реп не составляет большой проблемы.

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

Ну и очень хорошо угадывает.

Опять же, да, я иногда (раз в два года) предпочёл бы видеть возможность явно ему сказать "считай, что Foo переименован в Boo, а историю Moo, сделанного клоном из него, надо вести отдельно". В целом, не настолько проблема.

В общем вы правы. Но то, что Mercurial хранит весь граф модификаций иногда очень помогает. У меня есть форк проекта с GitHub (https://github.com/foal/gwt-time), структуру (не исходники) которого пришлось значительно изменить. Так вот git не может адекватно накатить изменения с оригинального проекта, а Mercurial легко. И это притом, что история коммитов просто идентична.

структуру (не исходники) которого пришлось значительно изменить.

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

А rerere в git не помогает? Вроде как раз для такого и задумана, после первой попытки, где надо таки разгрести вручную.

На счет rerere не знаю - не пробовал. У меня этот проект изначально был в Mercurial. А там все просто работает "из коробки".

Сейчас то я в основном с Git работаю - так просто по жизни проще.

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

Терять информацию - это _в основе_ всегда неправильный вариант. А найти изменённые файлы по диффам не менее простая операция.

И угадывает гит просто отвратительно.

И эти сущности не пропадают только от того, что кто-то решил почистить список указателей от неактуальных.

Именно что пропадают. Вмержили в транк - осталась только запись в сообщении коммита.

Терять информацию - это в основе всегда неправильный вариант.

Верно. Поэтому сообщение коммита начинаем с "MOO-1234: Fix moo frequency for most cow breeds". По этому "MOO-1234" выясняется и всё остальное. А как ветка была локально названа у конкретного коммиттера - уже неважно, да хоть "херня которая не даёт выспаться".

И угадывает гит просто отвратительно.

Повторюсь, я "за" сохранение метаинформации об изменениях, если коммиттер хочет этого и предоставляет её. Но при той юзербазе, что есть, отсутствие этой возможности означает минимальную потребность в ней. Какой-нибудь целевой плагин тут был бы, конечно, в тему.

насчет переименования файлов не сталкивался и не помню чтобы у меня гит хоть раз ошибался тут, но а в чем проблема сравнить снепшоты? так даже лучше: у вас могут быть разные алгоритмы и гит не развалится, если вы переключите diff алгоритм. а есть кстати интересные проекты, типа "Wilfred/difftastic" и они работают с гитом, жаль только не в режиме мержа. На сколько помню снепшоты были выбраны для быстрого переключения, иначе фейсбук опять бы выл) в общем решение использовать снепшоты было оправдано с точки зрения мейнтейнеров линкуса, а лично мне - все равно.

Он достаточно часто ошибается при каком-то большом рефакторинге, при котором меняется структура проекта. И неприятно там то, что очень часто всё выглядит вполне пристойно и легко можно не заметить, что файлы переименованы неправильно. С другой стороны результат-то от этого не меняется, и при реально больших изменениях в проекте одним комитом часто уже не важно, что именно там внутри. Но неприятно и может затруднить понимание изменений и поиск ошибок. Это если не нужно потом это рефкторинг ребейзить, иначе вообще ой-ой-ой.
Я гит раза четыре на таком ловил. Один раз было очень неприятно, так как рефакторинг был большой и в несколько стадий, с переносом результатов в другие ветки и там правильность дифа была принципиальна. Пришлось скатиться в лютый шаманизм и править переименования и перемещения файлов в кэше гита, что максимально кропотливо и муторно. Если не ошибаюсь, там Java была и и изменение структуры классов неизбежно приводило к изменениям структуры файлов, а нужно было несколько базовых абстрактных классов и интерфейсов изменить/разбить/объединить в одном комите, без всякой возможности разделить на меньшие такси (это же, блин, базовые интерфейсы и классы, они же сразу кучу изменений тянут по коду).

Ну у меня стабильно, когда разработка начинается с некоего шаблона формы, который потом обрастает всяким гит говорит "а я помню, это вы переименовали вон ту давно удаленную штуку, она с этого же шаблона начиналась" - с одной стороны.
А с другой - не смог поймать переименование папки с "Это исходный код нашего важного проекта" в "Src" - половина файлов переименование, вторая половина - удаление + создание и забудь историю.

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

Работал с mercurial, неудобная вещь. Форс-пуша нет, ребейз/объединение коммитов после пуша не сделать, правки к код-ревью остаются в истории мелкими коммитами. Для фиче-задач сами авторы mercurial советуют использовать bookmarks, что является аналогом веток в git, а branches для больших изменений. В итоге ветки-бранчи может и лучше чем в git, но пользы от них почти нет.

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

Нет, эти претензии сводятся к тому, что в меркуриале неудобно делать задачи.

Нормально в нем делать задачи. Только workflow не как в git. Проще ;)

Git тут ни при чем, я описал конкретные вещи, которые мне неудобны. Может вы считаете их удобными для себя, но они не станут от этого удобны для меня.

Уже 3 минуса. Контекст "неудобно лично мне" был задан фразой "[ваши] претензии сводятся к тому, что в меркуриале [у вас] не получится работать точно так же, как в гите [как вы бы хотели]".

Мне это было бы неудобно даже если бы кроме меркуриала не было других систем контроля версий. Так же как это было неудобно авторам расширения Evolve. Моя оценка меркуриала связана не с гитом, а с существованием неудобных для меня действий при работе с меркуриалом.

Только workflow не как в git. Проще ;)

Угу - "даём работать с распределённой базой как с простой централизованной, но с плюшками".

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

Да, на меркуриале сложно подкладывать остальным разрабам приключений с мержём, бисектом и ревью. Какой ужас.

Бисект ни разу не использовал, мерж и ревью есть и в меркуриале, никаких приключений с ними в гите по сравнению с меркуриалом не встречал. А проблемы с меркуриалом встречал.

Конечно не встречали, это ж не у вас после форс-пуша голова болит, и не у вас проблемы с бисектом после переписывания истории. Дожили, люди на Харе уже своим непрофессионализмом хвастаются.

Ну как это нет, я же не один делаю форс-пуш и переписывание истории. То есть по вашим словам я должен встречать эти приключения, когда кто-то другой так делает. Но такого не происходит. Неумение программиста построить такую логическую цепочку это профессионализм? Или может переход на личности это профессионализм?

Бисект ни разу не использовал

Это многое объясняет. Вымораживает, когда большой кусок работы в гите переписывают в один огромный коммит. История вроде как почище становится, но если вдруг нужен бисект - получаются поиски иголки в стоге сена.

Если чел свои локальные коммиты переписал - ну, имеет право. Хотя.. ну, история чище. И что это дает в плане полезности?

И что это дает в плане полезности?

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

Поэтому каждый коммит должен компилироваться и проходить тесты. А дальше деление на добавление функционала, удаление функционала, рефакторинг, стилевые правки всех видов, причём лучше всего в обратном порядке от того, как я перечислил.

Я объединяю коммиты, когда в одном написал "// TODO: вынести в отдельный метод", а в другом вынес в отдельный метод. Чем вам эта TODO поможет, если останется в истории? Кусок работы определяется задачей и логической связностью, иначе можно каждую строчку делать отдельным коммитом.

но если вдруг нужен бисект

Обычно если появился баг, я сначала ищу причину в текущей версии кода, потом делаю Annotate/Blame файла в IDE, и он показывает коммит, где этот участок кода появился. Исправление-то все равно надо делать для текущей версии. Для бисекта нужна воспроизводимость, а если она есть, баг проще найти в отладчике. Исключение это разве что какая-нибудь прошивка для устройства, где нет отладчика или логов, но это специфика проекта. В обычных проектах не представляю, зачем может понадобиться возиться с бисектом.

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

Тут всё правильно.

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

А вот тут - как раз лучше бисектом найти точку, где что-то сломалось, в любом случае, что у вас есть - отладчик, логи или что...

И что такое "обычные проекты"? Для меня вот "обычные проекты" это сетевые демоны всех видов, на протоколах, где тайминги критичны хотя бы в пределах единиц секунд. Отладчик там точно не подходит, а логи анализировать - только когда довёл до конкретных пары коммитов, где сломался тест.

как раз лучше бисектом найти

Почему лучше? Мне нужно найти место в текущем коде, а не коммит в истории.

И что такое "обычные проекты"?

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

Мне нужно найти место в текущем коде, а не коммит в истории.

Это если 1) вы реально понимаете, что происходит в текущем коде во всех его аспектах, и 2) это дешевле, чем проба на конкретной версии кода. Оба условия совсем не обязательны. Например, если вы используете чужое API, работа которого отклоняется от документации, или если, как у меня на днях, интерпретатор (PyPy) крэшится под нагрузкой при определённых условиях, надёжно воспроизводимых только на одном кастомере - ничего из простой пробы типа "место в текущем коде" у вас не сработает.

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

Ну это, вероятно, у вас единицы. У меня - таких проектов 90+%. А вот такого, где "ошибку можно воспроизвести в отладчике", не наблюдалось уже много лет.

Да, я в курсе, что по относительно свежей статистике 60-70% всех усилий программистов это веб. Ещё заметная часть на мобильные. Но если даже проектов моего типа 5%, это не единицы, это тысячи, если не десятки тысяч...

Вы его неправильно пользовали. В меркуриал практически всегда делаете бранч, в нем работаете, и после сливаете с основной веткой. Никаких ребейсов и форс-пушев вообще не нужно. Букмарки вообще не пользовали практически. Есть обычно три-четыре основные ветки, мастер и под пару релизов. Все остальное в "отдельных" репозиторииях разработчиков, где хранится их хлам из своих веток и прочей локальной белиберды. Перез пушем забираем нужную ветку или на нее переключаемся, сливаемся, пушим изменения.

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

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

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

Ну и в гит так же.

Никаких ребейсов и форс-пушев вообще не нужно.

Вам может не нужно, а мне нужно. Мне не нужны в истории опечатки и неправильные решения, которые исчезли в процессе обсуждения на код-ревью.

Перед пушем забираем нужную ветку или на нее переключаемся, сливаемся, пушим изменения.

Вопрос в том, что делать после пуша, если изменения требуют исправлений.

Это сильно облегчает задачу поиска изменений.

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

В hg есть аналог rebase и он намного проще и предсказуймей Git. И результаты его работы намного безопаснее. Ну, и использовать его там приходится гораздо реже.

Насколько я знаю, он есть только для незапушенных коммитов. Когда запушили, то всё, поменять ничего нельзя.

А как вы собираетесь менять историю запушенных комитов? Точнее, что вы ждёте на выходе? Способ есть, но он требует понимания своих действий. В Git тоже если историю запушенной ветки поменять, то всё очень сильно интересно станет. В Hg тут просто дополнительная защита от дурака получается - git начнёт ругаться при следующем пуше, а hg сразу.

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

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

Повторю. Git тоже запрещает то же самое, но при пуше или пуле. В git вам нужно будет использовать force при push/pull/fetch.
Hg же будет ругаться ещё на этапе внесения изменений, но вы точно также можете сделать force, что точно так же порушит ветки и потребует force при пушах и пулах.
В этом месте с учётом разницы в понятии "ветка" между git и hg вообще отличий нет, кроме того, что Hg предупредит вас перед выстрелом в ногу, а git после. И оба будут сопротивляться попыткам выстрелить в чужую ногу.

В git вам нужно будет использовать force при push/pull/fetch.

Я так и сказал, в git можно перезаписать историю на сервере с force push, а в hg нельзя. Я изначально говорил про force push, а не про обычный.

а о том, что хэши поменялись, вы не подумали

Подумал, и сказал, что мне нужно поменять хеши в ветке на сервере.

что точно так же потребует force при пушах и пулах

Я не знаю, что вы имеете в виду, со стандартным функционалом в hg нельзя перезаписать историю в ветке на сервере. Force push создаст новый head, что аналогично новой ветке, а старый останется, и удалить его нельзя. Оба head будут отображаться всем в истории, даже если им эта ветка не нужна, и создадут проблему какой из них скачивать, если после этого она им понадобится.

В git я делаю force push, и если ее никто не скачивал, никто про предыдущую версию и не узнает. Если после этого ветка кому-то понадобится, он скачает актуальную версию.

Стандартный кейс - запушили ветку, создали мерж-реквест, линтер в пайплайне показал ошибку, запушили исправление, тесты показали ошибку, запушили исправление тестов, отправили на ревью, ревьюер решил посмотреть ветку в IDE. В git это можно сделать с amend и force push, чтобы был один коммит, и ревьюеру не приходилось скакать туда-сюда по коммитам, собирая изменения в одно целое в уме. Или тому, кто потом будет делать аналогичную задачу или искать причину бага.

Да, извиняюсь, я думал про локальные изменения.

Иногда это полезная способность. Чаще всего над задачей работает один человек и все его пуши на сервер - это создание бэкапа его работы. Например банально завтра рабочий комп может не загрузиться и незапушеную работу надо начинать сначала, потому что она может потеряться. А потом можно "релизную" версию своей работы запушить с форсом переписав ее. Да так не стоит делать когда работаешь в команде, но так никто и не делает с общими ветками.

Эм, меняете фазу с public обратно на draft и спокойно правите / ребейзите коммиты. Потом пушите обратно. Или я чего-то не понял?

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

Как будто бы в гите вы изменяете существующую историю. Точно так же создаёте абсолютно новую.

Да, если скачать историю ветки origin/branch до и после force push, результаты будут отличаться. Это означает, что история, которая в ней существовала до этого, изменилась.

Это значит, что просто ветка переместилась на новую историю (так как ветка — это просто указатель на голову). Старая история никуда не делась (ну, до первого git gc), вы можете отыскать её в удалённом репозитории и восстановить при желании.

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

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

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

В hg есть аналог rebase и он намного проще и предсказуймей Git.

Вы допустили в фразе "кастрирован и импотентен" десяток ошибок.

И результаты его работы намного безопаснее.

Для безопасности в Git есть reflog и ветки, которые позволяют фиксировать любое состояние с возможностью его вернуть.

Ну, и использовать его там приходится гораздо реже.

Потому что всех устраивает, что в коммитах всё перемешано?

Никаких ребейсов и форс-пушев вообще не нужно.

Если ограничивать себя тем же уровнем функциональности и набором возможных flow, то и в гите их точно так же не нужно. Но Git позволяет сильно больше и гибче с минимумом усилий.

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

Я однажды сделал merge с совершенно другой кодобазой, и это сработало. О чём это говорит, кроме того, что я ошибся? ;)

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

В Git коммит тоже принадлежит ветке и имеет свой id. Что не так?

Нет, в git коммит не принадлежит ветке.

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

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

Знаю, работал с ним. Я же не сказал, что редактирования истории вообще нет, его нет после пуша.

by default, hg push promotes changesets from draft to public, and public changesets are immutable

О чем я и говорю.

The key to shared mutable history is to make the target repository, in this case test-repo, non-publishing. And, of course, we have to enable the evolve extension in both test-repo and dev-repo.

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

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

И честно говоря не понимаю, что хорошего в git.

​1. staging area. В Mercurial ничего подобного нет и не планируют. А это (вместе с interactive rebase) практически единственное, что позволяет легко делать чистые коммиты, а не такие, в которых намешало 100500 разных типов правок.

Для меня любая VCS, в которой этого нет, непригодна.

​2. Отсутствие зажима на определённые процессы разработки - который в Mercurial выглядит как множественные головы, тяжело изменяемый статус коммита вроде draft/public, и т.п.

Mercurial выглядит как "сэмулируем централизованную VCS на базе распределённой, но так, чтобы людям не надо было думать, что они делают".

staging area.

Лишний шаг, кмк.

git add list of files && git commit

hg commit list of files

А если использовать gui, то можно и отдельные diff'ы в отдельных файлах включать в коммит. И в git и в hg.

В hg неудобно переписывать историю на сервере, да.

А если использовать gui, то можно и отдельные diff'ы в отдельных файлах включать в коммит. И в git и в hg.

Вот.

​1. В Git для этого не нужен какой-то отдельный GUI, всё из коробки.

2. Git позволяет это делать (без GUI, `add --e`) даже не с отдельными диффами, а со строками. Критично, когда в таком диффе на 2 строки изменения, которые должны пойти на сервер, 3 на отладочную печать и 4 на комментарий для себя, что тут происходит и почему.

Может, для мелких дежурных правок такое и не нужно, но для задачи типа моей текущей сейчас, где сплошное "сигнал пошёл через обсервер в состояние вложенной FSM", мои комментарии "какого хера? уточнить это место" не должны идти в коммит даже если они на хинди.

​3. После я пересобираю правки и, например, переименования идут в один коммит, doxygen-пояснения - в другой (если их не было, потому что вот такая кодобаза), а функциональные правки - в третий. И только после этого я выставляю это в виде чистого, аккуратного результата, который легко ревьюить сейчас, читать даже через пару лет, прогонять через CI или bisect в любой момент.

А с Mercurial и его "вам это не нужно" в коммиты шли бы грязь, грязь и грязь из разнородных изменений и "я тут ещё одно место добавил и заодно функции описал".

В hg неудобно переписывать историю на сервере, да.

Польза от staging возникает задолго до пуша на сервер.

В Mercurial есть https://wiki.mercurial-scm.org/MqExtension, он намного гибче одной staging area, он позволяет иметь несколько таких area.
Ну и shelve еще есть, который больше подходит для стиля работы в HG - прячем все, что не идет в коммит, прячем все, что не идет в пуш. В Git же наоборот - надо указывать в стейжинг все, что идет в коммит, и ветки которые идут в пуш.

MqExtension

Я видел и пробно использовал его. Даже близко не похоже и очень неудобно.

Ну и shelve еще есть, который больше подходит для стиля работы в HG -
прячем все, что не идет в коммит, прячем все, что не идет в пуш.

Эта штука ещё тупее, практически равна stash.

В Git же наоборот - надо указывать в стейжинг все, что идет в коммит, и ветки которые идут в пуш.

Групповой push тоже есть, но не рекомендуется.

MqExtension - отличная вещь. В git мне её очень не хватает.

Довольно часто хочется иметь локальные изменения для версионных файлов, но не думать при коммите, что там по делу, а что локально для тебя. Так вот все эти вещи у меня в MQ хранились.

1 – поспорил бы. В hg у меня для таких случаев был подход: убираю в stash (ну или как он там назывался, давно дело было) все изменения, кроме тех, что нужно закоммитить (есть удобный инструмент для переноса их туда-обратно, вплоть до отдельных строк), компилирую-проверяю, коммичу, переношу из stash следующую порцию и так далее.

Т.е., грубо говоря, что не в индексе – того и в рабочей копии нет, можно проверять перед коммитом.

Было удобно. А с переходом на git – стал делать то же самое вслепую: выбрал файлы в индекс, закоммитил. Потому что процесс, аналогичный привычному, резко усложнился.

есть удобный инструмент для переноса их туда-обратно, вплоть до отдельных строк

А до правок текста тех строк, что отправляются (например, убрать комментарий типа "а вот тут главное")? Ну и это отдельный инструмент, а в Git оно в коробке.

Но я согласен в том, что проверять надо по уровню отправляемого коммита. Можно остальное скинуть в stash, но я предпочитаю делать `git co HEAD~1` или аналог, а потом вернуться. Stash он один на рабочую копию, а не на ветку.

Потому что процесс, аналогичный привычному, резко усложнился.

Там нет усложнения, просто надо делать чуть иначе. Для построчного stash я не знаю, а вот `add -i` и `add -e` решают задачу. А "набрать в индекс" желательно, чтобы проверить, что же собрал... ну или последовательно amendʼом набирать правки.

Процесс именно что усложнился. Сейчас мне проще с той же целью (чтобы что проверил – то и закоммитил) закоммитить во временную ветку, вернуться на рабочую и по частям переносить из временной, собирая отдельные коммиты. Заметное усложнение, так что я, честно говоря, редко так делаю, чаще коммичу вслепую :-)

Ну и инструмент у меня был как раз "в коробке", я в те времена ставил TortoiseHg, там работа с shelve (продвинутый аналог git stash) очень удобная.

Процесс именно что усложнился. Сейчас мне проще с той же целью (чтобы
что проверил – то и закоммитил) закоммитить во временную ветку,
вернуться на рабочую и по частям переносить из временной, собирая
отдельные коммиты.

Это удобный вариант, но совсем не обязательный. Я в большинстве случаев обхожусь без временной ветки.

я в те времена ставил TortoiseHg, там работа с shelve (продвинутый аналог git stash) очень удобная.

А TortoiseGit не даёт того же?

Ну, можно использовать stash вместо временной ветки, но в SourceTree нет такой свободы действий с ним.

TortoiseGit – не уверен, вроде нет (собственно, политика git с его индексом не способствует реализации такой фичи, это меркуриал с его mq как бы намекает – сделай, мол). В SourceTree – точно нет.

Но это не основная моя претензия к git (в конце концов не так часто приходится нарезать несколько коммитов из рабочей копии), так, мелкое неудобство. Просто вы сказали, что якобы в git это удобнее, что противоречит моему опыту.

Если я правильно понял, то в git можно делать "commit - stash save - compile - stash pop". Не знаю правда, зачем это нужно, обычно имеет значение только финальный вариант, потому что при работе с ветками для задач единица добавления и отката это мерж, а не отдельный коммит.
Хотя вместо этого в git обычно делают много мелких коммитов, потом интерактивным ребейзом объединяют в несколько крупных. Можно на каждом останавливаться и делать компиляцию или тесты.

Вот да, после полноценных бранчей гитовское поделие родом из CVS – боль... Но, увы, в битве систем контроля версий победил гит, приходится приспосабливаться, добавлять костыли...

Кажется, вся суть статьи находится в последнем абзаце. Остальное — куча слов, как кто-то куда-то пошёл, потом пришёл туда, там с кем-то поговорил, потом пришёл обратно к себе, там тоже поговорил.

Насколько я понял из объяснения - это такие атомарные PR, связные с какой-то конкретной фичей и ты работаешь с ними как будто уже всё смержили в мастер.

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

В какой-то момент нижние по стеку дифы апрувятся и мержатся в мастер

А что происходит со стеком, если нижние коммиты не аппрувнули, и их надо переделать?

Ребейзишься на диф в котором надо что то переделать, амендишь и сабмитишь снова.

Можно, в первом приближении, сказать, что основополагающим элементом является патч, а не слепок?

Если перенести это на вселенную Git, то под каждый чих в вашем коде, вы бы создавали новую ветку на основе предыдущей ветки, а пока предыдущую ветку ревьюит другой разраб, вы бы работали уже над следующей. И каждая новая ветка, которая сделана на основе вашей предыдущей уже содержит изменения из мастера. Таким образом, если вы пилите что-то большое, можно гранулировано выдавать изменения и постоянно трекать мастера, что в теории упростит вам жизнь во время финального мержа и деплоя. Ну и дальше можете сами понять насколько большой геморрой вас ждёт в такой системе, потому что после ревью надо пойти исправить другую ветку, смержить её в последующие ветки и довести изменения до вашей текущей ветки.

Судя по картинке из статьи по ссылке выше, все гораздо проще. Это как если бы мы в Git продолжали работать в ветке после ее мержа, и мержили еще несколько раз. То есть "коммит - мерж ветки в main - коммит - мерж ветки в main". Это не слишком сложно сделать в Git\GitLab\GitHub если очень хочется, просто зачем.

По-моему, всё именно так, как я описал.

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

Вообще, я считаю, что в GIT это, как видно, прекрасно реализуемо, и основная претензия к GIT в том, что они не подогнали систему под работу с гигантскими монорепозиториями. На сколько я знаю, GIT уже прекрасно работает с ними, и в целом довольно далеко ушёл в плане скорости работы за последние 10 лет. Но тут, конечно, надо учитывать, что у мега-корпораций требования специфические и примерять их платье на себя не надо.

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

В Gerrit существует уже 10 лет, типа такого: https://gerrit-review.googlesource.com/c/plugins/scripts/+/411660
см. "relation chain" и номера patchsetʼов: после правки в предыдущем в цепочке следующие надо обновить или локально с пушем, или через средства сервера. В Мете изобрели велосипед.

Насколько понимаю, в Git не так давно появилась опция --update-refs - с помощью нее можно обновлять все зависимые ветки при рибейзе основной.

А что это за "stacked diff" такой ?

Это как в Phabricator, видимо

это проэкты которые Мета выкладывает в опен соурс
внутри себя даже они хостятся на Меркуриале

ИЧСХ, не тупо снапшот, а с бранчами и коммитами.

Думается опенсорсные проекты врядли живут параллельно ещё и в меркуриале. Им же потом и публичные PR надо будет подтягивать туда. В них проблемы с монорепами скорее всего не существуют и поэтому там только отдельный ремоут имеется.

скажем так ... я точно знаю что такие проэкты как folly и buck живут "2ой жизнью" в 2х репозиториях
и да надо подтягивать PR если они интересны
так же как и обратно релизать из меркуриала в гит
но так как в Мете живут на монорепо, вред ли им хочеться не контролируемый "шум" из сообщества :-)

Ну тем не менее ультимативный заголовок "фейсбук не использует Git" это опровергает. Могли бы и в Mercurial выложить.

смотря как понимать "использует"
как фирма для своей работы - нет не использует
как фирма поддерживающая опен соурс сообшества , ну да как бы не усложняет жизнь :-)
ведь вроде "весь мир" пользуеться гитом ;-)
и можно даже сказать , что хорошо , что не стали навязывать всем меркуриал
a могли и на sourceforge там кажеться раньше SVN был :-)

Спасибо, интересная статья. В очередной раз убедился, что монорепозитории не нужны.

git мейтененер, перелогиньтесь

Fossil > Mercurial > Git > SVN > ручной учёт версий в папках > ничего > Plastic SCM.

TFS: я для вас какая-то шутка?

Просто никогда не использовал.

а в чем преимущество монореп? объясните

Или проблема была в том, что было лень ее делить

Сам работаю с такой штукой, но тут исторически так сложилось

Много мелких отдельных репо в какой-то момент начинают жрать слишком много усилий на поддержку этого хозяйства. Если в компании 5 репо - Вы эту проблему не почувствуете, а вот если их уже стало 50 - начнёте что-то подозревать.

С другой стороны, поддержка монорепо тоже требует немало усилий - в статье типичный пример этого.

Разработчикам Go в этом плане повезло: инструментарий языка "из коробки" неплохо работает с "как бы монорепо" - при условии что в этом репо исключительно проекты на Go. В этом случае удаётся получить лучшее из двух миров: и репо всего одно, и типичных для монорепо усилий оно почти не требует (максимум - нужно решить вопрос как раздельно деплоить только изменившиеся проекты, если их одновременный деплой неприемлем для бизнеса).

У нас уже 83. Когда ждать проблемы с их поддержкой? Там не такой уж хитрый тулинг для этого нужен. Можно даже делать часть реп на гите, часть на ртути.

У вас там половина мёртвых и работает 3 человека. Я думаю, сравнивать разработку никому неизвестных тулов с приставкой best-* с самой большой в мире соцсетью/маркетплейсом/богзнаетчто всё же не стоит. Тем более, им из своих репов не только min.js файлики генерить надо.

Это кто там мёртвый, например?

И при чём тут число мейнтейнеров?

И при чём тут самая большая бал-бла-бла?

Впрочем, а какие ещё они там файлики генерируют?

Статистика активности в репе. Прям живее всех живых.


Ну например, чем больше мейнтейнеров, тем больше коммитов, тем больше CI/CD пайплайнов завязано на репе и тд и тп. Если у вас 100 репозиториев, но 3 мейнтейнера кода, то там можно и ручками запускать скриптик для деплоя. А когда проект летит в прод каждые 10 минут и надо собрать из 20 разных реп код, то тут уже другой уровень тестов и всего.

Помимо этого, 83 мертвые репы - одно дело, а 83 живых - другое. Когда и документацией надо следить и за конфликтами и т.д.

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

А у вас там как-то на автомате все зависимости обновляются, в которых CVE всплывают? Или может вы там рисковые парни и просто работаете всегда с последней версией зависимости, пересобирая проект раз в неделю с молитвами, чтобы либа была обратно совместима? Или вот как насчёт обновить версию внутренней общей зависимости в 36 проектах и ничего не сломать? А продакты никогда не приходят и ничего не просят сделать в приложениях? А конфиги и пайплайны никогда не меняются? И даже нет тупоголовых начальников, которые меняются каждые 2 года, придумывая очередную архитектуру будущего для вашего приложения, а потом, вдруг, оказывается, что человек не хватает для реализации, денег не хватает, и еще ж поддерживать старое надо, но мы вот тут уже 55 реп новых создали под 55 священных микросервисов, из которых 2 всё таки пригодились, а остальные надо задокументировать, вдруг пригодятся в будущем.

Ага, рисковые. Пересобираем каждый день, при каждом пуше или вручную. Внешних либ мало, а те, что есть, сохраняют обратную совместимость. Каждый день обновляем, сами тоже ничего не ломаем. Вместо конфигов - соглашения. А "пайплайны" в отдельном репо. Тупоголовых не держим. Архитектуру без конца не меняем. Да, так тоже можно.

Примерно тогда, когда захочется:

  • Обновить конфиг CI/CD во всех репо.

  • Обновить какую-то популярную зависимость в тех (обычно - почти во всех) репо, в которых она используется.

  • Сделать какой-то рефакторинг во всех репо где есть подлежащий такому рефакторингу код.

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

  • Попытаться понять что у нас считается "текущими лучшими практиками" и по аналогии с каким из имеющихся 83 репо создавать 84-й репо с новым проектом.

Порядок, в общем, поддерживать сложно. А бардак развести легко.

Вы про монолит что ли говорите? Так вы там тем более никакого рефакторинга не сделаете.

Я говорю про кучку микросервисов на одном языке в одном репо. Рефакторинг в таких условиях делается просто прекрасно. Но и в монолите он делается ровно так же, не понимаю, какую именно проблему Вы тут видите.

Основные преимущества, которые микросервисы дают нам:

  • возможность использования наиболее оптимальных инструментов для конкретного сервиса, в том числе ЯП

  • полная независимость друг от друга

  • быстрое вхождение и рефакторинг

  • ownership

Микросервисы на одном языке, в одном репо попахивают:

  • Просто так поменять версию библиотеки не имея компетенции в других сервисах - рисковано. Нужно прогонять тесты на все остальные, а это долго и 100% покрытия не бывает.

  • Возникает риск использования общих модулей - антипаттерн в микросервисах. Теперь они у вас не самостоятельны, а часть так называемого distributed monolith.

Есть такое неписанное правило: работает - не трогай. Если у вас есть микросервис, который работает и никаких новых фич ему не нужно - его можно просто оставить в покое. В монолите такой опции нет.

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

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

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

Никто не мешает часть микросервисов написать на другом языке - просто они будут в другом (или других) репо.

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

полная независимость друг от друга

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

быстрое вхождение и рефакторинг

С этим как раз в одном репо на порядок проще.

ownership

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

Просто так поменять версию библиотеки не имея компетенции в других сервисах - рисковано. Нужно прогонять тесты на все остальные, а это долго и 100% покрытия не бывает.

Всё так. Но. Во-первых, в Go нет проблемы задать разные версии зависимостей для разных модулей в одном общем репо, а во-вторых иногда нужна именно гарантия обновления зависимости во всех проектах (если эта зависимость содержит изменения бизнес-логики нашей компании или исправляет проблему безопасности).

Возникает риск использования общих модулей - антипаттерн в микросервисах. Теперь они у вас не самостоятельны, а часть так называемого distributed monolith.

Какая разница лежит такой общий код в одном репо или в разных? Это никак не помешает его импортировать и использовать. Просто если он лежит в разных, то некоторые вещи обеспечить сложнее (напр. одновременное обновление всеми проектами такой зависимости). Это если такая зависимость осознанная и спроектирована архитектом. А против случайных неправильных зависимостей между разными частями кода (опять же, не важно этот код лежит в одном репо или разных) в Go придумали каталог internal/.

  • Массовые изменения, в том числе и конфигов, производятся авторефакторингом, который прописан первым шагом сборки во всех репах.

  • Нам не надо обновлять зависимости, они всегда берутся актуальные.

  • Один из репозиториев является шаблоном.

Когда что-то можно автоматизировать один раз и забыть - это круто, никто не спорит. Но всё ещё существует море задач, с которыми так поступить не получается.

Не всегда есть инструменты, которые бы позволили описать необходимый рефакторинг так, чтобы его можно было "не глядя" применить в 80 репо, и при этом ничего не сломать и не пропустить какие-то вариации кода к которым нужно было применить этот рефакторинг. К примеру, Go славится своими инструментами, и для него даже есть штук пять утилит для автоматизации рефакторинга - но пока ни одна из них не подходит для активного использования в описанном Вами стиле для любого рефакторинга. Пока ими можно делать только какие-то частные случаи, причём разными утилитами для разных видов рефакторинга, из-за чего массово эти инструменты пока вообще не используются.

Обновление зависимостей может без проблем пройти в 10 репо, а в 11-м что-то сломать. Поэтому нередко разные команды (отвечающие за разные репо) откладывают обновления зависимостей до момента, когда у них будет время разгрести вызванные этим обновлением проблемы. В Вашем случае это может работать потому, что команда одна и её готовность разгребать проблемы из-за обновления в конкретный момент времени относится сразу ко всем репо. Было бы много команд - это бы так просто не работало. Кроме того, идея механически при сборке обновлять зависимости обычно не работает, потому что: 1) получаем невоспроизводимые сборки; 2) сборка внезапно ломается и требует немедленного внимания игнорируя текущие приоритеты команды; 3) даже если сборка не ломается в новой версии зависимости может измениться поведение без изменения совместимости API, что может привести к неявным багам если одновременно не поправить свой код - поэтому перед обновлением (хотя бы критичных зависимостей) нужно читать changelog.

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

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

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

Чем раньше обнаруживается проблема, тем быстрее она решается. Fail Fast. А поведение фиксируется тестами, а не ченьжлогами.

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

Но это ещё цветочки - сейчас свою систему контроля версий допилю, так обновления вообще в реальном времени прилетать будут.

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

В шаблоне кода кот наплакал - там нет никаких "лучших практик" - просто костыли для гитхаба, которые он не позволяет вытащить из репозитория. Так-то у нас инфраструктура отделена от кода.

"Воспроизводимые сборки" противоречат идее "непрерывной интеграции".

Ни в коем случае! Воспроизводимость сборок означает только то, что сборка конкретного коммита и на машине всех разработчиков и на CI и сегодня и через год - даст одинаковый результат. Непрерывная интеграция - это про частые сборки всего проекта (т.е. попытку сборки и тестирования каждого коммита), а не про автоматическое обновление зависимостей прямо на CI. "Интеграция" в этом термине относится только к нашему коду, а не коду всех используемых сторонних зависимостей.

Вообще, забавно, как многие используют CI, не понимая, что это и зачем.

Вот да, тут не могу не согласиться. ;-)

А поведение фиксируется тестами, а не ченьжлогами.

Только в теории. А на практике тесты никогда не бывают настолько хороши.

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

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

Рекомендую всё же погуглить, что такое CI, а не выдумывать новые интерпретации для слова интеграция. А то о чём вы говорите - это сборочный пайплайн.

Ну а "воспроизводимость сборок" - бессмысленный карго-культ. Один раз собрал - получил артефакт и всё, зачем его снова собирать с тем же кодом?

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

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

Ну а "воспроизводимость сборок" - бессмысленный карго-культ. Один раз собрал - получил артефакт и всё, зачем его снова собирать с тем же кодом?

Хм.. если у вас из одного и того же кода могут получиться разные результаты. или не получиться.. ну, наверное так тоже можно - тесты прошли - скорее в production, пока не упали ;)

Ну вот недавно вышла новая версия тайпскрипта, которая поломала нам все сборки. Это позволило обнаружить и починить эту проблему раньше, чем кто-либо заметил, что несовместимость вообще имела место быть.

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

Иными словами:

Начальство: "почему релиз задерживаем?"

Программисты: "дык.. эта.. враги typescript сломали!"

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

Нам, татарам, что наступать - бежать, что отступать - тоже бежать. Можем фичи пилить, можем сборку чинить. А у ПМ от таких форсмажоров глазик дергается, и он требует избегать неконтролируемых внешних зависимостей. Понадобилась внешняя либа - сделали зеркало. Понадобилось ее обновить (не потому что версия поменялась, а потому что в changelog интересное) - внесли в план, обновили. Без форсмажоров.

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

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

Между запланированным апокалипсисом (под который выделены ресурсы, согласовано время простоя, и всякое такое) и внезапным, который случился в пятницу в 17:58, конечно, нет особой разницы.

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

Бизнесу все равно, хорошо я делаю работу, плохо, или совсем не делаю? Возможно ;) Но лучше расшифруйте это послание.

Кому-то из нас точно стоит погуглить определение CI, тут Вы правы.

Ну а "воспроизводимость сборок" - бессмысленный карго-культ.

Было смешно, спасибо! Я просто оставлю здесь эту пару примеров:

  • Два разработчика склонировали репо на одном и том же коммите и запустили сборку. У одного всё работает, а у второго - нет. Хм… как же это так получилось и что делать? Лучше только когда вчера вечером не работало, а с утра "само" починилось - ляпота же, работать в таких условиях, верно?

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

то, что не покрыто тестами сломается независимо от того прочитали вы ченьжлог

Вот только именно чтение changelog нередко подкидывает идеи что именно стоит дополнительно покрыть тестами перед обновлением зависимости - как раз для того, чтобы всё произошло именно так, как Вы описываете.

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

Поэтому должна быть не "максимальный приоритет", а "гарантированная полоса ресурсов". Даже 10% лучше, чем ничего. Иногда, конечно, нужно больше.

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

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

Я говорил про техдолг в принципе. В случае непредсказуемых внешних зависимостей - вы безусловно правы, приходится останавливать всё. Только в январе у нас такое было трижды - есть один проект, который вёлся с ежесуточным автомержем изменений от аплинка...

ну это наверное фейсбуку решать, а не гиту, в этом и фишка

Поищите, в Гугл не раз рассказывали, почему у них монорепа и чем это для них хорошо.

Гораздо меньше возни с зависимостями, исправление багов в библиотеках сразу распространяется на все проекты, но если где-то в другом проекте что-то сломали, то автотесты это сразу покажут и так далее.

Подход хороший, но должно соблюдаться много условий для этого.

Субмодули разве не решают сразу обе проблемы?

В исходниках андройда вместо субмодулей вкручен собственный костыль по имени repo. 1000+ субмодулей - неуправляемый адъ.

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

P.S. не к вам конкретно обращался, говоря "вы"

ад это ваше по

Несомненно адъ. Но другого андройда у меня для вас нет ;)

А какие еще есть варианты организации кода в огромном проекте? Без декомпозиции никак, клонировать 20 Гб чтобы поправить 2 строчки это еще хуже.

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

Я 40гб клоню на работе, чтобы 3 файлика поправить

Ни капельки.

Просто представьте себе сценарий - вы исправляете уязвимость в какой-то общей библиотеке. Как вам а) убедиться, что этот фикс не вызывает новых проблем в других проектах; б) доставить этот фикс на другие проекты (и не когда-нибудь, а поскорее).

--1 - Во всех проектах.

--2 - не поможет.

git submodule update обновляет зависимости моего проекта. Мне нужно выкатить в другие, о которых я не знаю.

Да, но в случае наличия суперрепозитория, в который остальные репы включаются субмодулями, это не выглядит большой проблемой, если update выполняется регулярно. По крайней мере, у меня на работе мы делаем именно так.

Регулярно делать update в 1000 субмодулей это ужасно. И совершенно неинформативно.

git -C submodule_path pull && git add submodule_path && git commit - так что ли? И так с каждым субмодулем?

git submodule update --init --recursive в суперрепо обновляет все субмодули разом

До какой ревизии обновляются субмодули?

<тут место для ответа>

А до какой ревизии нужно обновлять?

Ничего не понял. Всё обновляется до последнего коммита в отслеживаемой ветке.

То есть если в последнем коммите в субмодуле А внесены изменения (поле в базе данных переименовали), а в субмодуле Б соответствующих изменений еще нет, то сборка проекта автоматически ломается. Неудобненько получается.

КМК оно работает совершенно наоборот. Суперрепо помнит, какие ревизии субмодулей в него закомичены, и git submodule обновляет до detached head, а если хочется втащить изменения - git -C submodule_path pull
А если хочется, чтобы суперрепо эти изменения запомнил - git add submodule_path && git commit

Как вам а) убедиться, что этот фикс не вызывает новых проблем в других
проектах;

Ну давайте смотреть на процесс. Вот есть изменение в libmoo. У нас монорепа на 200k продуктов. Нам надо отловить те, которые зависят от libmoo напрямую - это шаг 1. Как мы будем это искать? Наверняка есть какой-то список. Вести его в монорепе или в разбросе - нет разницы, всё равно добавлять вручную. (В автопоиск по всему дереву - не верю.)

CI автомат? Ему точно так же нужен явный список. А после этого вытаскивать отдельные подветки толстой репы (не тащить же её целиком!) или отдельные маленькие репы - разницы нет, или второе даже проще.

На любой такой коммит CI должен всё проверить.

Шаг 2 - проекты, связанные с зависящими (типа сетевого взаимодействия) - тем более тоже на основании явно описанных связей.

Так для чего мудохаться с моно?

(На самом деле есть одна тонкость с субмодулями: для некоторых ситуаций нужно хукать замену URL к модулям. Но это в тысячи раз проще поддержки монореп.)

б) доставить этот фикс на другие проекты (и не когда-нибудь, а
поскорее).

О, вот тут действительно интересный вопрос. Если сводный коммит на библиотеку и все её зависимости, типа добавили один аргумент в функцию её API.

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

я бы не сказал что это удобно.
В одной монорепе лежит два проекта. Над ними работают разные команды.

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

По-моему намного удобнее когда используются две разные репы. Вот в одной пофиксили баг. Другая команда, когда ей нужно, обновила свою зависимость.


Тут наяву принцип уменьшения связности.

А как быть с базовыми (инфраструктурными) библиотеками, улучшение которых приносит пользу всем проектам? Аллокаторы, настройки системы сборки, конфигурации, авторизации, мониторинга, service discovery.

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

Ещё полезный эффект - появление глобального отношения порядка. Всегда можно сказать, что какой-то код влили в trunk в такой-то момент времени, и это позже или раньше какого-то другого кода. Это удобно, чтобы описывать правила вида "мы не поддерживаем совместимость по ABI такой-то системы дольше N коммитов и M времени" или "нельзя запускать на проде код старее коммита X".

А как быть с базовыми (инфраструктурными) библиотеками, улучшение которых приносит пользу всем проектам? Аллокаторы, настройки системы сборки, конфигурации, авторизации, мониторинга, service discovery.

У всех в зависимостях стоит "тащи последнюю версию из стабильной ветки" и в проецессе сбоки перед тестированием оно все и подтягивается.

Собственно, единственная проблема, что я вижу - это когда сборка всего настолько долгая, что в процессе сборки 'последняя стабильная' успевает пододвинутся и в результате в разных приложениях получается разная версия.

Правда, как именно монорепа помогает от этого - непонятно.

в процессе сборки 'последняя стабильная' успевает пододвинутся

Обновлять исходники в процессе сборки как то странно.

Обновлять исходники в процессе сборки как то странно.

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

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

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

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

а как быть, если в этих базовых изменяют интерфейс и в итоге все от этого страдают?

Не вижу проблемы вынести эту базу в отдельные репы. Если там изменяется патч версия, то можно спокойно обновлять особо не глядя - потом можно откатиться если что. Если обновилась минор, то можно посмотреть что полезного, может можно как-то свой проект оптимизировать за счёт функциональности новой - добавляем таску на обновление и доработку. Если обновилась релиз - добавляем таску на обновление и исправление для работы с новым интерфейсом.

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

вы предлагаете человеку, который работает над какой-ьо базовой частью, знать еще все проекты, которые от нее зависят?

Кажется так именно так и получаются ситуации, когда самый старый сотрудник ушел в отпуск и теперь никто не знает как тут что работает)

Я предлагаю воспользоваться инструментами (запросом к системе сборки, кнопкой references в IDE, глобальным code search), чтобы найти все проекты и поправить их. А потом запустить тесты, чтобы убедиться, что не стало хуже.

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

А как bus factor связан с широтой знаний? Если будет 2-3 человека, которые будут знать хотя бы в основе, что зависит от данного компонента и какие могут быть проблемы его изменения?

Да как они это знать то будут? Вот выкатили они свою клевую либу, засветилась она на техрадаре у десятка команд, одиннадцатая это увидела и включила себе. Если либа хорошо написана и дока есть, то эти 2-3 даже не заметят, что от них еще один проект/отдел зависят.

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

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

Все средства для этого обычно у команды есть, осталось только интеграции добавить...

Проще тогда в самом проекте, если он такой важный, перед мерджем PR проверять, что его известные зависимости не ломаются. Насколько я знаю, компилятор Rust-а, например, пересобирает все пакеты с crates.io, чтобы убедиться в отсутствии регрессий. Ну и далее вместе с мейнтейнерами зависимостей решать, что делать.

Проще тогда в самом проекте, если он такой важный, перед мерджем PR проверять, что его известные зависимости не ломаются.

Ну вот я и думаю, что это дело CI. Если что-то ломается на его тесте, отправка (push/merge/submit/как_хочешь_назови) не должна проходить (без разрешения кого-то очень важного). А вот как именно CI вычисляет, что зависит, должно поддерживаться как я описал ранее.

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

Вот в одной пофиксили баг...

...а во второй не стали обновлять зависимость, потому что и так все работает. Уязвимость? Производительность? Неважно.

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

...а во второй не стали обновлять зависимость, потому что и так все работает.

Какая именно механика этого 'забыли'?

Если там явно конкретная версия указана - то непонятно, почему при монорепозитарии эта версия станет вдруг исправленной.

Если же стоит 'последняя из...' - то при сборке эта самая последняя исправленная версия и подтянется.

Если же стоит 'последняя из...'

КМК ни git ни hg так не делают.

КМК ни git ни hg так не делают.

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

ну так это ответственность "второй" команды, а не первой

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

Или хуже

По вашему лучше сидеть и ждать, пока баг пофиксят в общей репе, чем откатиться назад до версии, где бага нет и спокойно развивать свой проект, пока его не пофиксят?

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

Уверен, они скажут вам спасибо

Не думаю что тут может быть единственный "лучший" вариант

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


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

Для больших корпораций выбор между монорепой и сотнями-тысячами репозиторев. Если обновили что-то «системное», то может потребоваться дорабатывать десятки репозиторев, которые ещё нужно найти-вычислить. И синхронная работа с изменениями по этим десяткам реп — та ещё дрянь.

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

Но цена у монорепы тоже «велика».

Легче состыковывать версии разных сервисов. Коммит в монорепе представляет собой набор софта в таком сочетании, по которому точно прогнались тесты (ну если не дураки в девопсе). Из коммита на сервера = должно работать. Иначе же нужно где-то как-то организовывать, что Попа версии 13 совместима со Стулом версии не меньше 4 и не больше 8 и Штанами только без начёса.

А если за этим не следить, то, несмотря на наличие системы контроля версий, становится нереально откатиться назад или поставить один сервис из альтернативной ветки. То есть её как бы и нет.

Ну так можно же сделать еще одну репу, Человек на стуле. В которой будет один файлик с конфигурацией: попа13 стул8 штаны_без_начеса_25
Создан будет на основании прогона пайпа с параметрами "попа_last стул_last штаны_без_начеса_last".
Если эта пайпа упадет, то будет сделана фичеветка "починить ласты", а мастер поменяется на конфиг с зафиксированным одним пакетом. Или двумя. Или тремя и не будет двигаться, пока фичеветки не починят.

В том, например, что если без монорепы для какой-то фичи нужно сделать изменения в X > 1 репозитории - мы получаем Х пуллреквестов, по каждому из которых отдельное ревью, которые надо еще и залить на прод потом +- одновременно либо в определенной последовательности. Неудобства и вероятность ошибки намного выше.

Но и с монорепой свои минусы.

почему там отдельное ревью?

потому что разные команды смотрят на то, как повлияет это измерение на конкретно ИХ проект.

Почему там одно ревью?

Потому что пара человек из команды X смотрит как изменение повлияет на ИХ проект. Тем временем люди из команды Y принимают последствия того, что никто не подумал как изменение повлияет на их проект.

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

Плюсы монорепы:

  1. Связи между проектами всегда в актуальном состоянии без лишних тех.задач или процессов.

  2. Одним коммитом можно внести изменения во все проекты и поревьювить разом.

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

Нельзя сказать, что для обслуживания монорепы совсем не нужен туллинг. Конечно, нужен. Вот хотя бы разграничить доступ и владение проектами, организовать селективную сборку. Проблемы, которые не пришлось бы решать не будь монорепы.

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

А если внесли изменение, которое в части подпроектов внесло ошибку? И обнаружилось это через месяц?

Так же разом всё откатывать назад у всех 100500 разработчиков? А если части из них нет/уволились/болеют/в отпуске?