company_banner

Arc — система контроля версий для монорепозитория. Доклад Яндекса

    Системы контроля версий уже давно стали повседневным инструментом разработчика. В больших монорепозиториях требования к ним оказываются весьма специфическими. Из-за этого компании либо адаптируют существующие решения, как это делает Facebook с Mercurial и Microsoft с Git, либо разрабатывают собственные системы: Piper и CitC в Google и Arc VCS в Яндексе.

    В докладе разработчик Владимир Кихтенко kikht рассказывает, зачем Яндексу понадобилась собственная система контроля версий и как она работает. Рассмотрим её со стороны рядового разработчика: как получить доступ к исходному коду, отвести ветку для разработки и интегрировать изменения в общую кодовую базу. Заглянем под капот — узнаем про внутреннее представление данных и их отображение в виртуальной файловой системе с рабочей копией. Обсудим трудности при реализации функций VCS в виртуальной файловой системе и при ленивой загрузке данных. Поговорим о том, как обеспечивать надежность серверной инфраструктуры репозитория. В конце можно посмотреть неофициальную запись доклада.

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

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



    Как мы дошли до жизни такой? Исторически этот монорепозиторий у нас жил в SVN. В нем практикуется trunk-based development. Веток нет за очень редкими исключениями. Весь код сначала должен попасть в транк, а потом зарелизиться.

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



    Каков масштаб нашей проблемы? Вот некоторые цифры: 6 млн коммитов, почти 2 млн отдельных файлов. Общий размер со всей историей репозитория — 2 ТБ. Чтобы было понятно, что эти цифры значат на фоне других типичных репозиториев, вот график. GitHub median — это медианный размер репозитория на GitHub, 1 МБ. 90-й перцентиль на GitHub — это то, что мои коллеги назвали «репозиторий сына маминой подруги». А все остальное — известные крупные репозитории.



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

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



    За время подготовки доклада git-svn, к сожалению, не смог сконвертировать весь наш репозиторий целиком. Сконвертировал некоторый срез небольшого числа коммитов, поэтому не могу оценить, сколько работают операции, связанные с историей. На одном отрезке они быстрые, а как оно будет на 6 млн коммитов — не очень понятно.

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

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



    Как мы этого достигли? Основная фишка: рабочая копия, которую мы создаем, не является настоящим файликом на диске. Это виртуальная файловая система. На Linux и Мас это сделано с помощью fuse, на Windows — с помощью ProjFS. Все данные загружаем лениво, поэтому используется столько места на диске, сколько на самом деле надо, мы не пытаемся загрузить все заранее. И всякие тяжелые операции мы выносим на сервер. В частности — операцию лога и еще некоторые.



    Интерфейс нашей системы контроля версий, по большому счету, повторяет Git, поэтому не буду показывать, как выглядит типичный воркфлоу. Представьте себе Git. Все то же самое: checkout для получения нужной ревизии, branch для создания веток, commit — для коммитов, точно так же поддерживается stash. Что дает этот подход? Мы существенно уменьшаем порог входа. С Git умеют работать большинство разработчиков внутри и снаружи Яндекса. Им не приходится учить ничего нового.

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



    Чуть-чуть расскажу про внутренности, про то, как это все работает. Начнем с модели данных. Модель данных у нас во многом похожа на гитовую, с некоторыми отличиями. Точно так же все объекты, которые внутри создаем, они иммутабельны, они адресуются хэшем своего контента, и внутри они хранятся в flatbuffers.



    Как структура выглядит? Есть объекты коммитов, у каждого коммита есть отдельный или несколько предков. И они таким образом выстраивают некоторый DAG (directed acyclic graph) истории.



    Что у нас есть и что не сразу появилось в Git — это generation numbers. По простому алгоритму мы считаем некоторое расстояние от корня дерева. Зачем нам это нужно? Это все в структуру объектов вшито, один раз зафиксирован, и больше никогда не меняется.

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

    Как это будет работать в наивной реализации? Как-то вот так: обойдем, и найдем наш нужный коммит.



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





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



    Это один пример отличия нашей модели. В Git эта штука и раньше поддерживалась, они использовали в качестве generation numbers timestamps, но это будет работать, только если времена создания коммитов согласованы с графом коммитов.



    К сожалению, для нашей истории репозитория это не так. Есть коммиты, которые получились в результате миграции другого репозитория, и время начинает в них идти назад. В Git эту штуку поддержали в какой-то момент, но она там не всегда применима, потому что в Git можно подменить объект коммитов другим локально. От этого страдает иммутабельность модели, поэтому те generation numbers, которые не записывают, они иногда не применимы к тому, что в них записано, это неправда. У нас такой проблемы не возникает.

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

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



    Что у нас не как в Git? Эту штуку мы называем copy-info. Если файл был скопирован в каком-то коммите, то Git эту информацию никак не сохраняет, и пытается потом эвристиками восстанавливать, когда показывает вам diffы и статусы. Мы эту информацию сохраняем в графе. У записей может быть некоторая ссылка copy-info на другой коммит, на путь внутри репозитория в этом коммите, по которому мы знаем, что в этом коммите этот файл был скопирован.

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

    Как устроены бэкенды? Если в Git распределенная система контроля версий, ему не нужны какие-то бэкенды. Мы ощущаем это особенно остро, когда GitHub не работает. Мы точно понимаем, что Git не нужны бэкенды. Наша система клиент-серверная, все данные она хранит на сервере, и доступность сервера нужна для того, чтобы скачать те объекты, которых на клиенте еще нет.



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

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

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



    Как наша система интегрирована с SVN? SVN-репозиторий продолжает жить. Более того, наша система контроля версий пока не самодостаточная. Как она в этой части работает? Исходно есть некоторый компонент Converter, который следит за состоянием SVN-репозитория и превращает коммиты SVN в коммиты Arc — нашей системы контроля версий.

    Дальше есть клиент, который монтирует (mount) рабочую копию и ходит за данными на сервер. Когда разработчик что-то коммитит, это отправляется сначала на сервер Arc, но чтобы эти изменения попали в trunk, нашу основную ветку, они должны обязательно пройти через систему пул-реквестов и систему код-ревью. Здесь возникает еще один сервис, который следит за ветками Arc, и если они обновились, отправляет пул-реквест нашей системе код-ревью. Дальше система код-ревью, когда принято решение, что этот патч нужно вмержить, коммитит его в SVN. Не совсем просто: она добавляет туда некоторое количество метаданных о том, что этот коммит на самом деле является мержем такой-то ветки из Arc. И дальше этот коммит уже видит конвертер, находит в нем эти мета-данные и создает коммит в сервере Arc. Такой получается круговорот коммитов. Поэтому пока мы без SVN жить не можем, потому что в SVN у нас лежит trunk.

    Основная ветка постоянно синхронизируется с нашим сервером, но напрямую в нее закоммитить мы не разрешаем.



    Про надежность бэкендов. Конечно, мы планируем, что все разработчики Яндекс будут пользоваться этой штукой, поэтому для нас важно, чтобы она не ломалась. Это такой внутрияндексовый стандарт: наши сервисы должны переживать выход из строя любого дата-центра. Система контроля версий — не исключение. Здесь нас очень спасает то, что YDB такое поддерживает. А наши бэкенды — stateless, там разные части чуть по-разному реализованы. Сервера, которые оперируют объектами Arc, оперируют ветками, они stateless, отреплицированы. Конвертеры, которые постоянно конвертируют из SVN, реплицированы по active-active схеме. Есть несколько одновременно работающих конвертеров, они одновременно конвертируют, и в момент, когда они пытаются обновить ветку Arc, они разрешают конфликты. У одного получилось, у другого не получилось. Он пытается конвертировать что-то дальше.

    Сервис пул-реквестов реплицирован по master-slave. Есть главный, работающий. Если он выходит из строя, через YDB выбирается новый. Там есть такая замечательная штука, как семафоры, у которых серьезные гарантии по доступности, надежности. Доступы к семафорам полностью сериализуются. Мы используем семафоры и для сервиса дискавери пул-реквестов, и для выбора лидеров.

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



    Например, мы открыли файл на запись. Когда мы открыли файл на запись, мы находим соответствующий блоб нашей объектной модели. Если необходимо — что-то подгружаем с сервера. Если мы физически создаем файл в специальном сторе, то все дальнейшие запросы, которые в этот файл идут, мы туда проксируем. Таким образом, пока не закоммиченые локальные изменения (в Git это называется unstaged) попадают во временное хранилище. Мы называем такие файлы материализованными.



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



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



    Следующая операция — arc status. Она интересная, потому что это та вещь, которая в обычных системах контроля версий на таких размерах оказывается медленной, потому что она вынуждена обходить все файловое дерево. Нам не приходится обходить все файловое дерево, потому что все запросы на изменение файлов проходят через наш fuse-драйвер, и мы сразу знаем, какие файлы стоит проверить на изменение. Проверяем то, что успели записать в индекс, и печатаем ответ.



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



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



    Почему это может не работать? Первая версия примерно такой и была. Проблема во всяких хитрых операциях типа arc reset –soft. Они переключают нам дерево переключают, но не материализуют файлы. Они продолжают существовать где-то закоммичеными. У нас есть еще untracked- и ignored-файлы, которые тоже нужно специальным образом обрабатывать. В этом месте мы много грабель собрали и в итоге пришли к тому, что все-таки во время чекаута мы должны взять дерево (сейчас — одну рабочую копию), взять дерево того коммита, на который мы переключаемся, взять индекс, и асе это аккуратненько помержить.

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

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



    В нашей системе контроля версий гвоздями прибита поддержка trunk-based development. Во-первых, то, что я уже рассказал: все изменения проходят через пул-реквесты и транк. Есть еще пара моментов. У нас нет поддержки групповых веток. Создаваемые в Arc ветки привязаны к конкретному пользователю, и только он может туда коммитить. Это позволяет нам избежать долгоживущих веток. В SVN такого особо не было, потому что там неудобно делать ветки. А в Arc их делать удобно, и если это не контролировать, мы боимся, что некоторые части нашего монорепозитория отъедут в свои ветки, и будут вести свою разработку там. Это противоречит модели, которую мы хотим делать.



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



    Какие у нас планы? 20% разработчиков монорепозитория уже пользуются нашей системой контроля версий. Мы уже уже вышли из какого-то младенческого состояния, это серьезно используемая система, выкинуть её просто так уже нельзя. Конечная цель — стать основной системой контроля версий в Яндексе. Мы должны как-то убедить оставшиеся 80% разработчиков, что мы достаточно стабильны, надежны и нами можно пользоваться. Ясно, что для этого нужно починить все баги и доделать те фичи, которые есть в Git.

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

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

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

    Предложение для обсуждения. Всю дорогу я повторял слова «как в Git». И в целом наш план остается прежним: интерфейсом повторять Git. Но чем больше мы это делаем, тем больше понимаем, что это не очень работает.

    Есть несколько проблем. Интерфейсы Git весьма низкоуровневые. Они предлагают чуть ли не операции, которые напрямую взаимодействуют с нашим графом объектов. При этом программисты хотят каких-то высокоуровневых операций. И далеко не каждый разберется с тем, какие и как нужно выставить аргументы команде checkout или reset, чтобы ничего не испортить в рабочей копии. Я это знаю, потому что занимаюсь поддержкой пользователей, которые переходят на нашу систему контроля версий. Регулярно говоришь людям: все как в Git. «Ну вот я это сделал, и все сломалось». В Git тоже бы сломалось.

    Для иллюстрации этой проблемы можно привести такой пример. Знаете такую нужную и полезную команду Git, как git begin-wave-stash?

    Из зала:
    — Очень полезная.

    — Как вы думаете, в Git такая команда вообще есть? В этом и проблема — без любимой поисковой системы вы не только не знаете, что она делает, но и не знаете в принципе, есть ли она. Ее нет, я ее только что придумал. Поэтому Git не лишен недостатков. И раз уж мы разрабатываем свою систему контроля версий, странно не воспользоваться возможностью их исправить. Спасибо.

    Неофициальная запись доклада
    Яндекс
    336,55
    Как мы делаем Яндекс
    Поделиться публикацией

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

      +2

      А как это по сравнению с VFS for Git (GVFS) от Microsoft?


      https://github.com/microsoft/VFSForGit
      https://devblogs.microsoft.com/bharry/the-largest-git-repo-on-the-planet/


      Чей велосипед лучше?

        +1
        > Каков масштаб нашей проблемы? Вот некоторые цифры: 6 млн коммитов, почти 2 млн отдельных файлов. Общий размер со всей историей репозитория — 2 ТБ.

        В статье Microsoft утверждается, что исходный код Windows — «всего» 300 Гб, что почти в 7 раз меньше.

        К тому же, здесь есть ещё другая проблема — если хочется работать со всем репозиторием целиком (т.е. не делать narrow clone и shallow clone), то git предполагает, что все объекты будут присутствовать локально, что ограничивает размер репозитория размером локального диска на машине. Если не рассматривать HDD, то типичный объем локального диска в современных ноутбуках составляет от силы 500 Гб, и репозиторий Яндекса туда просто не поместится. Даже если взять SSD на 2 Тб (вроде Apple сейчас даёт такую опцию для каких-то компьютеров), то ни для чего больше в системе места не останется.

        Я не утверждаю, что решение от Яндекса лучше чем решение от Microsoft: наоборот, мне очень нравится идея с git vfs. Просто оно не решает поставленную задачу самым эффективным способом с учётом стоимости SSD ёмкостью в несколько терабайт, которые иначе нужно было поставить каждому разработчику компании.
          +3

          Ну как бы VFS это вроде бы Virtual File System и решает она те же проблемы и вроде бы точно так же как и Яндексовый Arc. Т.е. ничего она целиком не высасывает.

            +1

            Да, Вы правы, я как-то не обратил на этот момент внимание, когда читал про git vfs. В любом случае, для репозитория Windows (в 7 раз меньше Яндекса) приводятся цифры по скорости работы git status, git checkout и прочего, и уже на этом объеме эти операции занимают по несколько секунд.

              +1
              git status, git checkout и прочего, и уже на этом объеме эти операции занимают по несколько секунд

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

          +1
          Мой опыт работы в геймдеве говорит мне, что размеры репозитория, указанные в статье микрософта, позволяют просто использовать Git на SSD с комфортной производительностью.
            0

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

              0
              просто использовать Git на SSD с комфортной производительностью.

              А связь с сервером?
              Все эти merge, push и т.п.
              +2
              VFS for Git — действительно очень интересный проект с похожими на наши целями и средствами. В Microsoft пошли несколько иным путем и добавляют виртуализацию ФС и ленивую загрузку объектов прямо в git за счет фигурного вырезания фильтров для sparse checkout и ignore файлов. Мы пробовали применить похожий подход в mercurial и довольно быстро поняли, что либо придется переписать почти всю vcs, либо мириться с кучей пограничных случаев, когда безобидная операция (тот же git log) начинает выкачивать все содержимое репозитория локально.
              Когда наш проект начинался еще одним недостатком GVFS было отсутствие поддержки linux, что для нас было критичным. Но с тех пор экспериментальная поддержка появилась.
                0
                А смотрели в сторону патчей для hg от Facebook? Насколько я понимаю, они тоже делали что-то похожее на то, что вам нужно.
                  +3

                  Да, смотрели. И да, это действительно очень похоже на то, что мы делаем. Но там до сих пор есть прекрасное https://github.com/facebookexperimental/eden/issues/7#issuecomment-473357543
                  Есть байка, что они выложили это в open source случайно и поэтому эти патчи невозможно собрать и использовать за пределами фейсбука.

              +19
              Вместо того, что бы разбить все это на мелкие репы и сделать инструмент высшего уровня для управления ими программисты продолжают умножать энтропию рожая N+1 систему контроля версий.
                +4
                Я полагаю, что Яндекс рассматривали эту возможность, и даже есть примеры больших репозиториев, которые так делают — это Chromium и Android, но согласно, например, этой статье, у этой модели тоже есть серьезные недостатки, например очень низкая производительность и необходимость скачивать эти репозитории локально, что весьма сложно делать, если репозиторий занимает несколько терабайт.
                  +1

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

                    0

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

                    +5
                    Вообще как я для себя понимаю основную мотивацию делать такое — это размен инженерного времени на написание навороченных тулзов для всего этого хозяйства вместо постоянной однотипной работы по обновлению библиотек в сотне различных репозиториев. Когда каждое такое обновление занимать может по несколько месяцев. Это автоматизируется частично, но всеравно будет куча автоматических коммитов с изменением версии пакета. Я работал в компании с очень небольшой кодовой базой, около 4-6М строк кода на питоне, разбросанного по примерно 300-400 репозиториям. И обновление какой-нить базовой библиотеки, очень непростоя и главное неинтересное занятие. А в Яндексе я подозреваю должно быть раз в 10 больше кода как минимум.
                    В монорепозитории же это будет 1 атомарто откатываемый коммит. Но нужно писать и поддерживать все эти тулзы. Что я думаю будет меньшей платой и с большим бенефитом потенциально.
                      +1
                      И обновление какой-нить базовой библиотеки, очень непростая и главное неинтересное занятие.

                      Которая решается пакетным менеджером и инженерными гайдлайнами (semantic versioning, использование "плавающих" версий зависимостей, либо даже просто ссылками на git ref).

                        0
                        Которая решается пакетным менеджером

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

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

                          +1
                          а еще версии и даже целые библиотеки умеют исчезать в никуда из реп внешних пакетных менеджеров.
                          Зачем внешних? Локально (в смысле в сети организации) поднять что гит-, что, например, Maven-репозиторий — не проблема. Артифактори там всякие, нексусы есть.
                            +1

                            Для этих целей у нас есть миррор для внешних репозиториев.

                            0
                            Как пакетный менеджер обновит зависимости в коде, обновит испольщуемое API для этой библиотеки, включит необходимые настройки и прогонит тесты, которые везде немного по-разному запускаются из-за множества команд и создаст PR?
                              +3

                              Оно обновится автоматом при деплое/билде, а затем прогонятся тесты.


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


                              Разве что для мультирепо PR-ов придется больше создать.


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


                              Бай зе вей — https://dependabot.com/

                                +1
                                Фиксирование версий библиотек вроде давно придумали. В монорепозитории оно должно работать точно так же.

                                Тут правда другая опасность есть. Застрять на версии 200х года и когда таки придется обновиться словить все проблемы совместимости за 15 лет разом. Но при должном отслеживании и регулярном обновлении все должно работать без проблем.
                            +1
                            В монорепозитории же это будет 1 атомарто откатываемый коммит.

                            Совершенно не факт.
                            https://habr.com/ru/post/435306/
                            https://habr.com/ru/post/436264/

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


                            Есть доводы и за и против монореп.

                            Исходя из того, что монорепы выбрали не самые глупые разработчики, которых могут себе позволить богатейшие Google, Microsoft и пр. — смысл в монорепах есть.

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

                            Что способно ухудшить итоговое качество кода, увеличить затраты на интеграцию.

                            VCS — это сервисное для разработчика ПО, обслуживающее потребности разработчиков.

                            Подстраиваться под менее удобный стиль работы из-за ограничений ПО?
                            Зачем? Если можно взять другое ПО или создать своё.

                            Пример из жизни:
                            git. Был создан Торвальдсом для удобства разработки Linux.

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

                              +2
                              Исходя из того, что монорепы выбрали не самые глупые разработчики, которых могут себе позволить богатейшие Google, Microsoft и пр. — смысл в монорепах есть.

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


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

                              в транк-бейзед, в целом, свой ворох проблем. Который накладывается на СВОЮ разработку. Я почти наверняка уверен, что яндекс может себе позволить разработку своей библиотеки каких-нибудь стандартных контейнеров для бОльшей части своих продуктов, а не тащить внешние зависимости. Но вот со штуками вроде фронтов на html+js такое уже не прокатит.


                              VCS — это сервисное для разработчика ПО, обслуживающее потребности разработчиков.

                              +1


                              git. Был создан Торвальдсом для удобства разработки Linux.

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

                                –1
                                Исходя из того, что монорепы выбрали не самые глупые разработчики, которых могут себе позволить богатейшие Google, Microsoft и пр. — смысл в монорепах есть.

                                Это звучит как карго-культ.


                                Карго-культ для Яндекса-то?
                                  0
                                  git. Был создан Торвальдсом для удобства разработки Linux.

                                  но опять же это не означает, что надо всех загонять в git.

                                  Мой посыл был о другом:

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

                                  Можно и наоборот — сделать инструмент под себя. Конечно, если у вас есть такая техническая и финансовая возможность.
                                0
                                del
                                +1
                                Предложение для обсуждения. Всю дорогу я повторял слова «как в Git». И в целом наш план остается прежним: интерфейсом повторять Git. Но чем больше мы это делаем, тем больше понимаем, что это не очень работает.


                                Вот с этого момента хотелось бы поподробнее :). Почему не работает? Какие команды вы планируете поддерживать, а какие нет? Мне кажется, если ограничиться некоторым подмножеством высокоуровневых команд и не предоставлять низкоуровневый интерфейс, то должно быть достаточно похоже для большинства, без необходимости полностью имитировать объектную модель Git (которая довольно плохо масштабируется для совсем больших репозиториев).

                                Также, возможно я что-то пропустил, но хотелось бы узнать, как вы реализовали аналог «git log » и «git log »? Как отслеживаете переименования? В «оригинальном» git log это затратные операции, потому что git не хранит информацию о переименованиях отдельно, и соответственно git log при всём желании не может показать историю для конкретного файла без того, чтобы сканировать все коммиты в репозитории.
                                  +4

                                  В целом вы правы, мы планируем поддерживать высокоуровневые команды git по степени востребованности нашими пользователями. Но, например, пользователи переходящие с svn сильно удивляются количеству действий, которые надо сделать для отправки небольшого изменения на ревью: arc checkout -b + arc add + arc commit + arc push + arc pr create — это 5 действий вместо одного привычного им svn commit. Поэтому мы движемся в сторону создания интерфейса более высокого уровня, который упрощал бы типичные сценарии. Это в чем-то похоже на подход git-flow с поправкой на то, что у нас trunk based модель.


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

                                  0

                                  Arc?! Это случайно не тот самый Arcanist, a command-line interface to Phabricator?

                                    +5

                                    Судя по всему, не тот же самый. В Facebook не git, а mercurial (и это здорово, потому что последний и быстрее на порядок, и удобнее на таких объемах и при безветочной схеме с trunk-based development, которая, похоже, становится популярным стандартом де-факто).


                                    Думаю, что arc, что arcadia обыгрывают имя сооснователя Яндекса.

                                      +1

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


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


                                      А вот по части невозможности глобальных рефакторингов, автор имхо просто ошибается. В нашем репозитории я вполне проделывал вещи вроде grep | xargs | sed, разве что вместо простого grep там был вызов серверного code search, а все остальное естественным образом быстро работало в нашей vcs и загружало только затронутые файлы. Невозможность сделать ревью таких изменений до возникновения конфликтов мне тоже кажется надуманной.

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

                                        Я думаю, что принципиальным вопросом является то, как сделан процесс разработки — разрабатываем ли мы коробочный продукт для наших заказчиков (и тогда мы связаны необходимостью поддержки нескольких версий) или пилим какой-нибудь SaaS (который может существовать в единственной версии — текущей, т.е. крайней, но с поддержкой, например, нескольких версий API). Это два разных подхода и мне было бы очень интересно услышать, как, например, в рамках trunk-based легко и безболезненно держать разработку нескольких версий одного коробочного продукта (ну, например, кликхаус вполне подойдет, наверное?).

                                        +1
                                        По сути там написано «если у вас настолько много кода, что не помещается на машину разработчика, то монорепозиторий потребует дополнительных ресурсов для поддержки» (второй довод — про сильную связанность — очень надуманный). Впрочем, при таком объёме кода нужны инструменты и для работы с набором репозиториев (или зонтичным, без разницы). И пусть мы выделяем на эти инструменты меньше ресурсов, расплачиваются за это остальные разработчики.

                                        Я постоянно вынужден создавать ветки в нескольких репозиториях и отправлять их на ревью. Да, всё заливается вместе, CI, вот это всё, но это менее удобно, чем создать ветку в одном репозитории. Навигация по ФС усложняется, т.к. есть лишняя вложенность. Бывает, что команды не выносят общий код в общее место, а коммитят в «свой» репозиторий, чтобы «упростить» ревью, из-за чего другие даже не знают про то, что уже что-то написано, и создают велосипеды.

                                        И это при том, что я лично выкачиваю все репозитории из зонтика — места хватает, ничего не тормозит.

                                        Да, монорепа требует дополнительных усилий. Но эти усилия даже близко не сопоставимы с усилиями Гугла (или даже Яндекса), т.к. и кода меньше. А когда кода столько же, то и средства по идее должны быть.
                                          0
                                          Я постоянно вынужден создавать ветки в нескольких репозиториях и отправлять их на ревью. Да, всё заливается вместе, CI, вот это всё, но это менее удобно, чем создать ветку в одном репозитории.


                                          Вы путаете теплое с мягким. Ветки вас заставляет создавать git flow, а не сабмодули. Не используйте git flow — не будет и миллиарда веток в сабмодулях.
                                          Вообще, «монорепе» обычно противопоставляется «микрорепы», когда границы проводятся по каждой библиотеке. Истина же где-то по-середине — слишком мелкое деление так же вредно как и отсутствие его. Qt5 разделена на примерно 50 сабмодулей, кажется, это слегка перебор (и, естественно, идут разговоры о «монорепе», как будто по середине ничего нет)
                                            0

                                            А как тогда работать вне концепции веток? Мастер ветка и переключение функционала через feature gate ?

                                              +2
                                              Мне очень нравится gerrit. Проблема в том что он проприетарный (в том смысле что нет опен сорс аналога уровня GitHub), страшный как смерть (сейчас уже получше, но всё равно...), поэтому о нём мало кто знает и почти никто не пользуется. Мой поинт в том, что гитхабовская схема с pull request, которая _форсит_ создание feature branches — не единственная возможная. Просто там ветки — это деталь реализации, зачем-то торчащая наружу.
                                              В общем и целом Gerrit по процессу очень похож на внутренний яндексовый велосипед для ревью и прекоммит проверок — по факту вы и там и там коммитите «напрямую в транк» безо всяких pull requests и фича веток.
                                              Что, конечно же, не отменяет возможности создать feature branch по желанию. Просто Gerrit не навязывает схему с pull requests и\или git flow.
                                                0

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


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


                                                Заодно — phabricator смотрели?

                                                  +1
                                                  В общем. Положим, разраб взял какую-то фичу...


                                                  В зависимости от размера проекта, есть два подхода. В случае небольшого проекта, если изменения не конфликтуют по коду (это Gerrit сам ловит) и мы условно не боимся, что изменения конфликтующие, их можно протестировать независимо и потом влить в мастер. Если изменения таки конфликтуют, можно указать разработчику на зависимость и попросить отребейзить изменение на свежий мастер. В общем, ничего нового.
                                                  Второй подход заключается в том, чтобы делать staging branch — когда пачка изменений разных разработчиков как-то черри-пикается друг на друга и проверяется в таком виде перед мержем в мастер. Минус что если один коммит ломает что-то, то остальные надо stag'ить заново. Плюс — мы всегда собираем то, что будет в итоге в мастере. Также, этот подход необходим, когда не хватает железа тестировать каждый коммит отдельно. Пример — всё та же Qt, матрица тестируемых систем достаточно большая и нет возможности прогонять тесты ~6 часов для каждого коммита в отдельности.
                                                  К сожалению, я не в курсе, сколько второй способ требует усилий, чтобы его реализовать (никогда администрировать gerrit не приходилось).

                                                  Заодно — phabricator смотрели?

                                                  Нет, но коллега на текущей работе пользуется и очень хвалит. Сами мы вообще на svn пока что=(
                                                  +2
                                                  Изменения, состоящие из нескольких локальных коммитов, в gerrit попадают через git push. Это по сути создание ветки, пусть и без явного указания имени.

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

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

                                                  Да и обновление в gerrit'е происходит с использованием change id, что куда менее удобно, чем с force-with-lease обновить feature-ветку с конкретным именем.

                                                  Что касается миллиарда feature-веток, то изменения перед проверкой и вливанием можно автоматически переставлять на конец нужной ветки, а саму ветку удалять после вливания. Ничего лишнего — ветки только для версий, а также для фич в разработке или на ревью.

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

                                                  Если же не нравятся отдельные merge-коммиты в истории, то у них есть плюс — все изменения по одной задаче сгруппированы вместе. Имеет смысл настроить в CI non-fast-forward merge как минимум для изменений из более чем одного коммита, а с учётом специфики git'а, в котором не сохраняется метаинформация о ветках и тегах (автор и, особенно, время изменения), лучше даже поступать так и для изменений из одного коммита.
                                                    0
                                                    У меня возникает стойкое ощущение, что у вас слишком гранулярное деление на сабмодули. Естественно, никакой геррит вам тут не поможет (и никакой тулинг не поможет, если конечно вы не гугл и у вас есть десятки человеколет на написание этого тулинга). Только это не проблема сабмодулей, это проблема того, как вы их готовите.
                                                    Если вы думаете, что в Яндексе постоянно вот так вот приходят и делают коммиты затрагивающие всё дерево сорцов, то вы ошибаетесь — даже «банальное» переименование Stroka в TString делалось поэтапно (если мне не изменяет память).
                                                    А между сервисами совместимость _обязана_ быть между версиями. Я конечно мог бы прийти в соседнюю команду и на их java написать использование нового поля, закоммитить всё это одним коммитом… Но какой в этом толк, если 2 сервиса всё равно должны работать в любой комбинации (старый-старый, старый-новый, новый-новый...) на случай факапа и возможного отката одного из них? А еще релизный цикл разный — один сервис катается быстрее чем второй…
                                                    Собственно «правильное» деление на сабмодули должно быть по слабо зависящим друг от друга частям — например, репозиторий с сорцами 3rdparty вполне такой кандидат. Или ассеты, если вы разрабатываете игру.
                                                    Если у вас одна фича постоянно требует связанных коммитов — подумайте о слиянии зависимых сабмодулей в один. Или подумайте о том, почему эти репозитории так зависимы — может, надо использовать другой формат общения между ними?
                                                      0
                                                      А между сервисами совместимость обязана быть между версиями. Я конечно мог бы прийти в соседнюю команду и на их java написать использование нового поля, закоммитить всё это одним коммитом… Но какой в этом толк, если 2 сервиса всё равно должны работать в любой комбинации (старый-старый, старый-новый, новый-новый...) на случай факапа и возможного отката одного из них? А еще релизный цикл разный — один сервис катается быстрее чем второй…

                                                      Как это у вас реализовано? В случае транк-разработки я вижу вариант только при инстанцировании новой версии сервиса попросту копировать все дерево файлов из старого каталога service.v1 в новый каталог service.v2
                                                      Но тут, прошу прощения, я слаб. Ибо в гите все как раз просто — заводишь два отдельных бранча и понеслась.

                                                        0
                                                        Сервисы общаются между собой при помощи неких форматов. Это может быть жисон, когда один сервис запрашивает по http данные у другого. Это может быть protocol buffers, когда один сервис подкладывает файлики другому. Это может быть YT… Вариантов куча. Большинство форматов умеют в опциональные поля — жисон, протобуф. Собственно, при добавления нового поля потребитель проверяет — а новое поле есть? — тогда используем его, иначе работаем «по-старинке».
                                                        Сильную попаболь доставлял MMS — там да, чтобы сделать новую версию, приходилось натурально копипастить исходники. Но это, скорее, исключение (к счастью, было нужно редко) и, возможно, flatbuffers тут подошли бы лучше.
                                                        Без такой совместимости не получится сделать надежную систему — у вас факап на проде, а откатываться нельзя или очень сложно.

                                                        PS: Но я уже больше года не работаю в Яндексе, так что мои знания могут быть немного устаревшими=)
                                                          0

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

                                                            0
                                                            Да, новую реализацию стараются прикапывать рядом, не ломая старую. Но оно обычно не противопоставляется старому функционалу, а расширяет его.
                                                +1
                                                Мы работаем не по git flow :)
                                                Но, как и комментатор выше, я не могу представить себе модель разработки без использования веток (при условии, что есть предварительное ревью кода).
                                                  +1
                                                  Я не призываю полностью отказаться от веток, я ярый противник «технических» веток, когда feature branch создается на любой чих просто потому что «так все делают» или потому что так хочет тулинг (github).
                                                  Надо поддерживать N предыдущих версий — вперед, релизные ветки рулят.
                                                  Начали работать над новой версией библиотек — вперед, долгоиграющая feature branch.
                                                  Портируете проект с автотулз на cmake? Тут тоже пригодится feature branch.
                                                  Вот только не надо создавать ветку чтобы убрать\добавить пробел в выражении=)
                                            +6
                                            Я правильно понимаю, что вы так и не импортировали репозиторий в Git? И поэтому не знаете, может он достаточно хорошо работает на ваших объёмах и вам не нужно изобретать велосипед?

                                            А вот цитата:
                                            За время подготовки доклада git-svn, к сожалению, не смог сконвертировать весь наш репозиторий целиком.

                                            То есть вы сначала сделали свою VCS, потом начали писать про неё доклад и только потом попытались протестировать работу Git'а?
                                              +5

                                              Мы тестировали работу гита на отдельных фрагментах репозитория и результаты нас не радовали. Для доклада мне хотелось получить какие-то числа для всего репозитория, чтобы было проще сравнить разные vcs.
                                              У нас нет оснований предполагать, что от конвертации всего репозитория git магическим образом начнет работать лучше. Там будут те же принципиальные проблемы, что и с mercurial — многие операции требуют обхода всего дерева каталогов и их трудоемкость растет с размером репозитория. Те цифры производительности, которые мне удалось на скорую руку получить, эти предположения подтверждают.

                                                +2
                                                Если сделать svn co Аркадии, потом сделать git init && git add && git commit (то есть, импортировать всё без истории коммитов), а потом попробовать с этим поработать, то, например, git status будет занимать 3 секунды. Не очень удобно.
                                                  +1

                                                  Ну кстати git status, который отрабатывает за 3 секунды — это не так уж плохо для git-репозитория такого размера :). Вот с вещами вроде git log и git blame у вас правда будет всё очень грустно :).

                                                +1

                                                Ребята, вы всё делаете не правильно. И сейчас я объясню почему.



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


                                                мы не пытаемся загрузить все заранее. И всякие тяжелые операции мы выносим на сервер

                                                Замечательно. Почти любые операции прибивают разработчика к серверу и зависят от скорости интернета. Современные разработчики вспоминают эту особенность SVN как страшный сон, а вы так и застряли в прошлом веке, не сумев в децентрализацию. Работа в поезде, самолёте, в окружении 30 файфай-точек, в подвальном кафе, через забитый открытый файфай? Не, только в офисе и по проводу.



                                                И какой смысла повторять чей-то апи не полностью? И при этом брать за объект для подражания набор команд, который не ругал за бестолковость только ленивый. Почему было не взять за основу тот же Меркуриал, который более дружелюбен к человекам? Более того, дальше вы пишете:


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

                                                То есть, вы не проанализировали ещё, как это всё будет использоваться (а иначе бы уже реализовали нужные команды), а уже взялись за реализацию. И как результат — реализация "веток" совершенно не учитывает то, как эти ветки будут использоваться:


                                                Довольно важная операция для системы контроля версий — это поиск наименьшего общего предка для двух коммитов.

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



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

                                                  +1

                                                  Этот комментарий сделал мой день. Спасибо.


                                                  По поводу ребейз вопрос. Я его не люблю. По двум причинам. Первая — это отличный способ зафакапить всю историю, но тут совет один — не делайте ребейз на ветках, отличных от своей личной. Т.е. ребейз на мастере или dev ветке — запрещаем. Вторая ипостась ребейза — это выравнивание своей истории коммитов при мерже в мастер и схлопывание истории разработки фичи в один meaningful коммит. Не вижу здесь проблем, кроме того, что ребейз слишком мощен и может отстрелить обе ноги, но это явно лучше, чем 100500 веток на графе коммитов и лишние MR-commit'ы

                                                    0
                                                    Вторая ипостась ребейза — это выравнивание своей истории коммитов при мерже в мастер и схлопывание истории разработки фичи в один meaningful коммит.

                                                    А какие причины использовать rebase вместо merge --squash?
                                                      0

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

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

                                                    Вот релизные ветки и trunk/master переделывать действительно не стоит, ну так у многих систем есть защита от force-изменения веток, подпадающих под указанный regexp.

                                                    P.S. Насколько я знаю, с чем у текущей монорепы Яндекса проблемы, так это с тем, что rebase -i нет, а для причёсывания перед вливанием бывает полезно.
                                                      0
                                                      Вот релизные ветки и trunk/master переделывать действительно не стоит, ну так у многих систем есть защита от force-изменения веток, подпадающих под указанный regexp.

                                                      Все так. Так и должно быть.


                                                      А что плохого в том, чтобы проверяемые изменения ребейзить?

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

                                                          +2
                                                          По первой ссылке:
                                                          Автор почему-то считает, что в rebase коммиты добавятся в конец веток. В реальности же есть CI, который не даёт вливать ветку с ошибками. В этом случае коммит g можно не ставить в конец, а объединить с тем, где добавили ошибку, и только после этого повторно отправить на вливание. Лично я чаще всего именно так и делаю.
                                                          Проблема с bisect'ом преувеличена. Не знаю как где, но у нас применяется редко, т.к. постоянные пересборки и проверки занимают достаточно много времени, обычно быстрее найти ошибку в дебаге.
                                                          Также там говорится, что исправление конфликтов во время мержа проще. Но почему? Будут всё те же конфликты, вот только не разбитые по изменениям, как при rebase, а одной кучей. И править придётся сразу кучу, а не по частям. Да и читать историю, когда исправления конфликтов не внесены в оригинальные коммиты, а вынесены в отдельный merge-коммите, куда сложнее.

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

                                                          Я пользуюсь rebase (часто интерактивный) с момента перехода на git в 2012 году, проблемы возникают очень редко и всегда быстро отлавливаются. Зато вот с merge-коммитами проблем хватает. Например, если blame указывает в merge-коммит, то сразу не понимаешь причину изменения логики, приходиться реально открывать историю и просматривать коммиты в ветке. Инструменты часто не умеют отматывать blame назад по нелинейной истории. Часто в merge-коммите не указана задача, т.к. подливается, например, ветка версии. Или разработчик может внезапно закоммитить merge-коммит как обычный, т.к. «что-то поменялось, а снова мержить не хотелось», убив тем самым всю ветку целиком, схлопнув все изменения и потеряв всю метаинформацию — реальная история, к сожалению.
                                                            –3

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


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


                                                            Ну и про CI — вы реально предлагаете гонять CI по всем коммитам, а не только по последнему? И это в ваших условиях, когда "пересборки и проверки занимают достаточно много времени". Впрочем, вам бы стоило прежде всего решить проблему долгой сборки, так как она много чему мешает. Не только использованию bisect.

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

                                                    Самое читаемое