От каждого по способностям, каждому по потребностям. — Карл Маркс, «Критика Готской программы»

После прошлой статьи про Klipper самым частым возражением было не «вы неправы». Самым частым было: «Ну и чо такого? Форкнул, сделал патч, пользуешься». Причём писали это люди, которые сами так живут, — и которых, судя по всему, совершенно не беспокоит, что их труд утонет в миллионах форков и никогда никому не пригодится.

Так что такого? Чтобы ответить, придётся сначала договориться, что вообще значит «открытый».

Публичный — не значит открытый

Откройте определение Open Source от OSI — там десять критериев. Откройте четыре свободы FSF. Все четырнадцать пунктов — о том, что гарантируется вам: читать, менять, распространять. Ни один — о том, что проект обязан принять ваш патч. Оба канона описывают артефакт и молчат про процесс.

Кто-то это понимает и говорит честно. У SQLite на странице о лицензии так и написано: Open-Source, not Open-Contribution. Код открыт, патчи не принимаются, спасибо, до свидания. Valetudo из прошлой статьи — та же честность другими словами. Контракт объявлен, вопросов нет.

Но в бытовом смысле «опенсорс» склеивает две разные вещи. Первая — право читать и форкать, и оно гарантировано лицензией. Вторая — возможность занести обратно, и лицензией она не гарантирована вообще. Первое — это публичность кода. Второе — его открытость. И Эрик Реймонд ещё в «Соборе и базаре» описал ровно эту разницу: собор с опубликованными чертежами не становится базаром.

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

Пока это абстракция. Посмотрим, как выглядит один «просто патч» на самом деле.

Как выглядит «просто патч»

Прямо сейчас я заношу в OpenWrt роутер Keenetic KN-1012 (здесь и далее — он же Netcraze NC-1012 после ребрендинга, одна железка независимо от шильдика).

Взялся, потому что железка того стоит: крепкая, современная, недорогая и с SFP-портом. В SFP-клетку встаёт провайдерский модуль, и роутер заменяет собой GPON-терминал от оператора. Пользователей GPON, которым это нужно, огромное количество — в РФ, Грузии, Армении и много где ещё. Драйверы почти везде понятные, я честно рассчитывал на быструю работу.

Проблема оказалась не в драйверах, а в том, как их склеить между собой. У роутера особенная топология: комбо-порт SFP/Ethernet, и переключение между ними надо делать ещё в U-Boot, формируя под выбранный режим соответствующий DTS. Это уже не «добавить device tree по образцу», это работа на трёх уровнях сразу.

Но главное даже не сложность. Главное, что за словами «поднять борду» скрывалась не одна задача, а семь. Сама борда поднимается отдельно — настолько, насколько это вообще возможно. А то, что сетевая подсистема ядра в глаза не видела железо за свитчом, — это отдельная проблема ядра, к борде она отношения не имеет. То, что на кинетиках вообще случаются коллизии MAC-адресов, — отдельная. EEE на свитче — отдельная. Опечатка в ширине SPI-шины, которой четыре года, — отдельная. Каждый из этих треков заслуживает жизни сам по себе: он чинит что-то не только для моей железки и потому идёт в апстрим самостоятельным PR или серией. Общего зонтика у них нет и быть не может. Но по-настоящему рабочий девайс получается только тогда, когда все они сходятся воедино.

Если вам интересно технопорно — добро пожаловать под спойлер. Если нет — достаточно запомнить число: семь.

Как «порт на вечер» стал патчсетом в ядро

Порт KN-1012 не начинался с нуля. К августу у меня уже был свой первый порт — Keenetic Buddy 6, #23727, четыре устройства на одном dtsi (KN-3411, KN-4410 и их Netcraze-близнецы), — и свой драйвер SPI-NAND HeYangTek, принятый в linux-mtd. На них я наработал всю механику: формат прошивки zyimage, TFTP-recovery без консоли, NMBM. То есть я не прыгал в неизвестность — я трезво оценивал, на что иду, потому что один раз уже прошёл этот путь. Buddy 6 при этом до сих пор ждёт ревью с июня — но это уже про первую статью.

Отсюда оценка на старте, девятое августа: «тот же mt7981, тот же NMBM, тот же TFTP-recovery, единственная настоящая неизвестная — какой 2.5G-PHY стоит на комбо-порту и как заведён SFP-кейдж. Станет ясно, порт это на вечер или на месяц». Стало ясно. На месяц с лишним.

Топология. Два часа над вендорским DTS — и картина ясна: GMAC0 → свитч MT7531, а пятый порт свитча — один SerDes, который через мукс на GPIO 27 уходит либо в SFP-кейдж, либо в Airoha EN8811H и дальше в медный 2.5G RJ45. Статически развести нельзя — SerDes общий. Прецеденты в дереве: TP-Link FR365 с тем же тандемом MT7981+MT7531, и Turris Omnia, в чьём мейнлайновом DTS так и написано: «until kernel supports this configuration properly, U-Boot has to enable the sfp node». Выбор среды на каждой загрузке делает загрузчик, потому что runtime-переключения у phylink/DSA нет. Отсюда chainloaded U-Boot: вендорский bootm грузит мой U-Boot вместо ядра, тот читает mod-def0 и выбирает конфиг из dual-FIT — медь или SFP.

Форк-предшественник. В тот же день нашлась ветка @Linaro — он начал порт KN-1012 ещё в феврале. DTS, светодиоды, рецепт образа — всё это взято оттуда, с атрибуцией. И два патча ядра, один на 370 строк, который подменял phylink у живого DSA-порта по поллингу mod-def0 — там, где фреймворк ничего не гарантирует. Последние коммиты ветки назывались try to fix sfp/lan4 и test lan4. Финал — SFP-only, медный phy-handle закомментирован. Плюс модель NAND в его DTS байт-в-байт совпадала с соседней платой и не совпадала с реальным чипом — копипаста. Это и есть тот самый «рандомный форк с половиной работы» из середины статьи. Разница только в том, что я знал, чего в нём не хватает, — и то потому, что автор сам объяснил в чате.

Чейнлодер. Первая прошивка — цикл перезагрузок, консоли нет. UART я паял дважды: кочергой вместо паяльника и смолой, которую я надоил с сосны вместо канифоли, — это не шутка, — с Flipper вместо терминала. Активности нет ни на одном пине, а третью попытку я делать не стал: этой кочергой лучше не запаять, а плату добить можно. Отлаживал по светодиоду: 68-байтные «маяки» на ARM64, мигающие GPIO. Выяснилось, что вендорский bootm требует ARM64 Linux Image header. Потом — что при минимизации defconfig выпал CONFIG_TIMER: get_timer() не движется, и любой цикл «крутись до таймаута» бесконечен. Один корень для трёх «разных» зависаний — чтение NAND, опрос свитча по MDIO, tftpboot.

Медь. Plain-образ загрузился, но lan4 не появился: DSA привязывает PHY на probe свитча, через две секунды после старта, а драйвер EN8811H — модуль и грузится позже. Порт валидируется с generic-PHY, а тот не умеет 2500base-T: -EINVAL, порт помечен unused. Встроить драйвер в ядро не спасает: он грузит прошивку в probe, а /lib/firmware ещё не смонтирован. Во всём дереве OpenWrt EN8811H на порту DSA-свитча не стоит нигде — все держат его на GMAC, где привязка ленивая. Никто так не делал. Шесть версий DSA-патча за одно утро, включая ту, после которой плата не вернулась и я доставал её через recovery кнопкой. Шестая — подключать PHY на ifup, когда модуль уже в памяти, — заработала. Линк не поднялся, пока я не вмешался: полярность GPIO 27, аналитически выведенная из четырёх источников, на железе оказалась обратной.

Потом медь умерла. Линк есть, трафика нет, битые кадры. Сток показал, что железо живое — значит, баг мой. Фикс airoha,pnswap-rx — перепутанная полярность RX у SerDes-пары — я попробовал и «опроверг» за двенадцать секунд. При том, что первый линк на этом PHY поднимается 55 секунд. Археология по логам сборок нашла, что единственный образ, гнавший 938 Мбит/с, был не чистым: в нём сидел тот самый pnswap. Одна строка в DTS, iperf 2.34 Гбит/с, три ребута из трёх. Вот что значит «патч лёг, а функционал не гарантирован, и проверять — нужна экспертиза».

Ядро. DSA-патч «подключать PHY на ifup» ушёл в netdev серией из трёх — с двумя попутными фиксами, найденными по дороге. Andrew Lunn ответил на следующий день: «this is not guaranteed to work… think about the case of NFS root». Тем же вечером — «moving the binding of MAC to PHY into open is wrong… I need to think on it for a while». А ещё через день прислал архитектуру целиком и попросил найти в ней дыры: до загрузки прошивки чип — не PHY, а микроконтроллер в бутлодере, и описывать его надо отдельным MDIO-устройством, которое грузит прошивку и публикует PHY на вложенной шине, а phylink получает свойство slow-to-probe и ждёт. От его «have a think» до моего «I built it» прошло сорок часов: два варианта реализации, матрица тестов, аттач PHY на 7.0358 секунды во всех бутах с разбросом 47 микросекунд — это тик поллера, а не гонка. Ещё два письма — и 29 августа ушёл RFC из девяти патчей. Мой первоначальный подход в ядро не пошёл — и правильно: он ломал NFS-root. В OpenWrt он временно живёт как локальный carry — до тех пор, пока архитектурный вариант не доедет до мейнлайна.

Два попутных фикса стали отдельной серией в net. Первый: phylink запоминает указатель на PHY до последнего шага, который может провалиться, и при провале второй disconnect отцепляет PHY повторно и отпускает уже отпущенные ссылки. Второй: PHY, прошедший цикл привязки к generic-драйверу, навсегда остаётся в поллинге, и настоящий драйвер никогда не видит прерывание из device tree. Paolo Abeni попросил Fixes-тег — археология привела к коммиту рождения phylib: обе половины бага там с первого дня. На первый патч Lunn поставил Reviewed-by.

Третья серия — EEE. Драйверы mt7530 и mtk_eth_soc заполняют lpi_capabilities, но не lpi_interfaces, а phylink считает MAC умеющим EEE только при обоих. Итог: EEE выключен на каждом порту каждого mt753x и каждого MAC mtk_eth_soc с момента конверсии драйверов, и из юзерспейса не включается — phylink идёт по другой ветке и вызывает phy_disable_eee. Daniel Golle поймал в обосновании фактическую ошибку про 2.5G, а Paolo — попросил ограничить фикс подтверждёнными ревизиями SoC. Подтверждать пришлось самому: MMD-регистр 3.1 бит 11, Tx LPI indication, читаемый 30-строчной утилитой через SIOCGMIIREG, потому что на плате нет ни devmem, ни python. Тридцать потоков по триста пакетов под взведённым LPI — 9000 из 9000.

Что в итоге не про мою плату. Первая серия — для любого чипа, которому нужна прошивка, чтобы стать PHY. Вторая — для любого PHY с драйвером-модулем на несмонтированном rootfs. Третья — для всех MediaTek-свитчей и SoC-MAC-ов разом. Плата их просто вскрыла.

В OpenWrt это две платы — шесть устройств, если считать все шильдики, — и пять отдельных проблем: Buddy 6 в #23727, KN-1012 в #24820, #24623 про генерацию MAC-адресов, #24819 с бэкпортами phylink/phylib и carry DSA-патча, #24863 с бэкпортами EEE, #24809 с опечаткой в ширине SPI-шины. Про опечатку стоит рассказать отдельно: ей четыре года и четыре месяца. Она приехала в дерево в апреле 2022-го вместе с бринг-апом mt7986 — от инженера самой MediaTek, из вендорского референсного DTS, сразу в двенадцати экземплярах. Все последующие платы честно копипастили её из референса, и все эти годы устройства молча жили на однобитной SPI-шине вместо четырёхбитной. Никто не заметил, потому что «медленно, но работает» не выглядит как поломка. Копипаста референса — самый эффективный вектор доставки опечатки в дерево, и один фикс в апстриме закрывает её на всех платах разом: на Teltonika RUTC50 чтение 64 МиБ ускорилось с 13.5 до 5.7 секунды. Рядом — патч в firmware-utils: в форке утилиты zyimage потерялась конвертация порядка байт, и тридцать устройств в дереве заточены под неправильный порядок. Плюс патч в U-Boot с поддержкой SPI-NAND FM25G01B и FM25G02B — потому что чип, который стоит в моём экземпляре, Linux знал, а U-Boot нет. Серии в netdev: RFC из девяти патчей, phylink и phylib, EEE. Было ещё несколько — старые дизайны и отвергнутые версии, их не считаем.

Это больно, интересно и полезно. И я мог бы просто остановиться на собственном форке — как мне и советуют.

Что получит тот, кто «просто форкнет»

Что тогда получил бы человек, который этот форк найдёт? Посмотрите на список выше. Это не один патч. Это семь самостоятельных треков, и вот что с ними не так: без соседей каждый из них как-то работает. Основной PR — и железка загружается. Без фикса генерации MAC — работает, пока виртуальный интерфейс не получит тот же адрес, что и физический, и трафик не начнёт ходить не туда. Без фиксов PHY — работает, пока не начнёт флапать линк на комбо-порте. Без бэкпорта DSA — работает, но не так, как должна. А опечатка в ширине SPI-шины вообще не проявляется ничем, кроме того, что обращения к флеш-памяти вчетверо медленнее, чем могли бы быть.

Теперь представьте человека, который через год находит мой форк. Скорее всего, он найдёт основной PR — он самый заметный. Соберёт прошивку. Получит железку, у которой не работает половина того, ради чего всё затевалось, — и не будет понимать почему. Честно признаюсь: в моём основном PR стоят кросс-ссылки на остальные шесть треков. Но они там потому, что мне было выгодно повысить видимость, и адресованы они ревьюерам, а не тому, кто через год ищет прошивку. Это мой выбор, а не норма. В общем случае никаких ссылок нет: борду поднимает один человек, баг в OpenWrt чинит другой, подсистему ядра правит третий, и они не знают ни друг о друге, ни о том, что их работы связаны. Обозначить семь треков в трёх проектах как единый набор негде — разве что в личном блоге или в рецепте на 4PDA. Треки встречаются только в мейнлайне. И там же выясняется, каких проблем удалось избежать — точнее, не выясняется: они просто сходятся в релизе, и никто никогда не узнаёт, что без одного из них половина устройств не работала бы. Вот этого форк не может дать в принципе.

Допустим, наш человек всё-таки нашёл рецепт и собрал набор вручную. Дальше — конфликты между патчами, которые писались в разное время под разные ветки, плюс три серии в ядре и патч в U-Boot из других репозиториев. Но конфликты — не самое дорогое. Патч, который чисто лёг на ядро через две, три, четыре версии после того, как был написан, не обязан работать: git проверяет текст, а не поведение. Подсистема под ним могла поменять семантику, и патч будет молча делать не то. Значит, после каждого ребейза — ещё пара часов тестов. И то при условии, что есть экспертиза понять, что именно тестировать: я 55-секундный линк «опроверг» за двенадцать секунд, а уж я в этом железе сидел месяц. Даже если бы я вёл всё это одной веткой без цели попасть в мейнлайн, каждый релиз стоил бы мне часов ребейза и нескольких итераций тестов. Человеку со стороны — в разы дороже.

Вот что означает «форкнул и пользуешься» на практике: пользуешься ты. Один. Пока не надоест ребейзить. Ядро не получает багфиксы в DSA. OpenWrt не получает железку. Люди с провайдерским терминалом не получают ничего. Дни моего труда, если утрировать, не делают мир лучше — они делают лучше мою домашнюю сеть, и на этом всё.

«По потребностям» без «по способностям»

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

Ошибка не в индивидуальном расчёте, а в горизонте. Патч в форке стоит не вечер, а вечер, умноженный на количество релизов, которые тебе придётся пережить, — потому что ребейз не бесплатен, а конфликты копятся. Патч в апстриме стоит неделю ревью один раз — а дальше его ребейзят, чинят и переносят на новые ветки чужие руки. Обычно уже на втором-третьем релизе форк дороже. А если то, что ты пишешь, уже кем-то написано и лежит в рандомном форке — ты вообще платишь дважды: за то, чтобы переизобрести, и за то, чтобы это потом тащить. Ревью в мейнлайне больно, но это одноразовая боль. И боль эта — не ритуал, а сигнал. Если ваш код действительно хорош, лишён багов и сделан по правилам подсистемы, ревью пройдёт быстро и почти не заденет. Больно становится ровно там, где код плох — и в форке вы об этом тоже узнаете, только позже и дороже: не от ревьюера в письме, а от железа, которое повисло, потеряло данные или выпустило волшебный дым. Ревью — не налог на вход, а дополнительный гард, который в форке просто не предусмотрен. Форк — это подписка.

Не верите мне — поверьте OpenWrt. Это огромный проект с сотнями контрибьюторов, и он сам по отношению к ядру — даунстрим. Так вот: OpenWrt не любит таскать патчи. В общем случае, когда ты приносишь им фикс для ядра, тебя просят хотя бы попытаться отнести его в апстрим. Это не вежливая просьба — это структура репозитория. В target/linux/generic три каталога: backport — уже принято в ядро и бэкпортировано, pending — отправлено в ядро и ждёт, hack — то, что в апстрим не занести, и его держат минимальным. Чтобы твой патч попал в pending, он должен быть отправлен наверх. При каждом бампе ядра патчи, доехавшие до стабильной ветки, выкидываются — в коммитах так и пишут: «removed, upstreamed». Проект, у которого рук больше, чем у любого из нас, посчитал и решил: таскать патчи слишком дорого, даже для него. Именно поэтому мои фиксы в phylink и EEE лежат в OpenWrt как бэкпорты и pending — а не как ещё один слой патчей, который пришлось бы ребейзить вечно.

Если это не по карману OpenWrt, то одиночке с форком — тем более.

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

Вот здесь и стоит вернуться к эпиграфу. «Форкни и пользуйся» — это половина формулы. Каждому по потребностям — да, бери, лицензия разрешает. А от каждого по способностям — нет, зачем, мне и в форке хорошо. Это не коммунизм. Это его половина, и именно та, которая без первой не работает.

Только вот «общественное благо» — плохая мотивация для хакера с паяльником. Он не партийный работник.

А что с этого лично вам?

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

Я нарушил кучу правил. Не специально — у них просто принято иначе, чем везде, и этикет там не считывается с первого взгляда. Я писал слишком длинные ответы в тредах. Я нарушал netdev-правило двадцати четырёх часов — не слать новую версию серии раньше, чем через сутки. И так далее по списку. Никто не послал меня читать документацию. Меня подхватили, направили и потратили — реально потратили — часы своего времени на то, чтобы дизайн моих патчей стал правильным. Не «примите как есть», а «вот как это надо делать, и вот почему». Лучший пример — судьба моего DSA-патча. Он работал: плата поднималась, порт жил. Andrew Lunn, мейнтейнер PHY-подсистемы, ответил, что подход неверен в принципе — он ломает NFS-root, — и написал «мне надо подумать». Через два дня он прислал полную архитектуру решения и попросил найти в ней дыры. Не отфутболил, а спроектировал за меня то, что я спроектировать не мог, — потому что не знал подсистему так, как знает он. Через сорок часов я ответил «I built it», а ещё через четыре дня в netdev ушёл RFC из девяти патчей по его дизайну. Это не ревью. Это школа. Сеньорское ревью такого уровня в коммерческой разработке стоит очень дорого, а здесь его дают бесплатно любому, кто принёс работающий код и готов слушать. Кстати, по его же замечаниям commit messages переписывались от версии к версии: «оставь в сообщении только “почему”, механику расскажет дифф».

Второе — бесплатный мейнтейн. После мержа ваш код перестаёт быть вашей проблемой. Когда подсистему рефакторят, ваш драйвер правит тот, кто рефакторит. Когда меняется API — переносят. Драйвер NAND, который я занёс в ядро в июне, будет жить там дольше, чем я буду помнить о его существовании, — и чинить его буду не я.

Третье — репутация, и она не абстрактная. Тот самый фикс опечатки в ширине SPI-шины задевал двенадцать плат, и большинства из них у меня нет. Я попросил в OpenWrt-чате помощи с тестированием — и на следующий день со мной связался Routerich, вендор, чьи роутеры были в списке, и предложил отблагодарить железом: два роутера. Не за поддержку его устройств — я их никогда в руках не держал, — а за фикс общей опечатки, который задел и его. Репутация работает и в другую сторону — когда ты оступаешься. Недавно я нарушил правило в репозитории Gateway API. Мейнтейнер не отшил меня и не отправил читать CONTRIBUTING — он написал: «делай так же, как ты делаешь это в Cilium». Я активен в обоих проектах, и к моменту ошибки у меня уже была репутация. Ошибку простили не потому, что она мелкая, а потому что за ней стояла история полезных контрибьюций. Люди, которые приходят ко мне с PR и ишью в мои личные проекты, всё чаще пишут что-то вроде «спасибо за работу над Cozystack, слежу за тобой». Апстрим делает тебя видимым, а видимость приводит к тебе и контрибьюторов, и вендоров. Репутация в опенсорсе — валюта, и зарабатывается она только на общественном поле. В форке тебя никто не видит.

И четвёртое, самое незаметное: ваша железка переживёт ваш интерес к ней. Форк умирает, когда вам надоедает. Апстрим — нет.

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

А если проект не отвечает?

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

«Никто никому ничего не должен» — вечный аргумент, и для SQLite он верен: они ничего не обещали и ничего не берут. Но если проект собирает звёзды, берёт спонсорские деньги и зовёт людей контрибьютить — свою половину сделки он уже получил. Отвечать на входящее — пропозалы, ишью, PR — это вторая половина. Не альтруизм, а обязательство по сделке. Что именно брать — то, что соответствует миссии, нужно большинству или просто нравится мейнтейнеру, — его право. Молчать годами — нет.

В марте 2024-го я открыл PR в официальный helm-чарт Cloudflare — cloudflare/helm-charts#69, опция отключить дефолтную 404-ю. Два с половиной года. Ноль ответов от мейнтейнеров. И не потому, что репозиторий мёртв: в сентябре 2024-го они смержили чужой #74 — заходили, видели очередь и прошли мимо. После этого — два года без единого содержательного коммита. Зато в треде моего PR собрались люди с той же болью, и последний комментарий там — чужой человек постит ссылку на мой форк как решение. Так я стал мейнтейнером собственного чарта, который люди ставят вместо официального. Второй PR в ту же организацию — cloudflared#1582, горячая перезагрузка конфига, с января: ноль комментариев. Два PR, два игнора — это уже не случайность, это способ ведения проекта.

А вот как выглядит проект, который отвечает. У Obico нет экспертизы в Helm, а я не хотел держать чарт у себя — сценарий Cloudflare мне не нужен ни с какой стороны. В июне я открыл ишью с предложением официального чарта, через три недели принёс PR — его приняли. Потом подписанный OCI-артефакт, потом arm64-образы, потом стартап-пробы. Я напросился к ним в мейнтейнеры и в хоббийное время развиваю чарт у них, а не у себя. Ни у кого нет форка. Двадцать три дня от идеи до принятого чарта — против двух с половиной лет тишины. Разница не в размере компании. Разница в том, отвечает проект или нет.

Заметьте: я не требую, чтобы приняли. Я требую, чтобы ответили. Отказ с аргументацией — нормальный исход. Молчание — нет. Как проектам не утонуть в потоке PR и какие из них брать — отдельный разговор, и он будет. Но реагировать на инпут — часть контракта, если ты назвался открытым.

А если не хочешь — скажи, как SQLite. Это честно, и тогда все знают, что делать: форкать без иллюзий. Сам по себе форк — не зло.

Когда форк — это нормально

Форк — легитимный инструмент, и случаев, когда он уместен, больше, чем можно подумать после всего, что я написал выше. Объединяет их одно: форк — это осознанный выбор там, где донести до мейнлайна заметно дороже, чем самому нести бремя поддержки. Ключевое слово — осознанный: цена бремени посчитана заранее, а не выяснилась постфактум.

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

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

Когда дельта архитектурная, а не фичевая. В прошлой статье я рассказывал про blockstor — LINSTOR-совместимый control plane, переписанный в кубернетес-нативной парадигме. Это не патч, это другой проект, и через PR такое не заносят.

Когда проект тебе не рад. Сказал честно, как SQLite, — молчит, как Cloudflare, — или просто не хочет твоих патчей по политическим или каким угодно ещё причинам. Тогда форк — единственный выход, и заходить в него надо без иллюзий: это не «мой код доедет позже», это «мой код живёт здесь».

И самый очевидный случай, о котором забывают: форк как площадка. Без форка ты и PR не отправишь — так устроен GitHub. Ветка в форке, где патч живёт, пока идёт ревью и тесты, — это не форк в смысле этой статьи. Это транспорт до мейнлайна.

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

Играть вдвоём

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

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

Каждому по потребностям лицензия уже гарантирует. От каждого по способностям — это за вами.

Комментарии (33)


  1. grarchangel
    04.09.2026 14:18

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


    1. lexfrei Автор
      04.09.2026 14:18

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

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


      1. ValdikSS
        04.09.2026 14:18

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


        1. lexfrei Автор
          04.09.2026 14:18

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


          1. ValdikSS
            04.09.2026 14:18

            Позвольте показать вам мой пример вопиющей несправедливости: https://github.com/OpenPrinting/cups-filters/issues/541

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

            Несмотря на название функции (print odd/even), оба автора (а один из них не только автор софта, но и автор стандарта) утверждают, что функция изначально предназначалась для ручной двусторонней печати, и для этой цели она работает корректно.

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

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


            1. lexfrei Автор
              04.09.2026 14:18

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


              1. ValdikSS
                04.09.2026 14:18

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

                Так зарабатывайте, берите деньги за поддержку кода.


                1. lexfrei Автор
                  04.09.2026 14:18

                  Стараюсь, уже десяток лет стараюсь :)


    1. dmitrytheman
      04.09.2026 14:18

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


  1. rsashka
    04.09.2026 14:18

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


    1. lexfrei Автор
      04.09.2026 14:18

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


      1. rsashka
        04.09.2026 14:18

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

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

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


        1. lexfrei Автор
          04.09.2026 14:18

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


          1. rsashka
            04.09.2026 14:18

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

            Увы нет. С вашими буквами это вообще никак не связано.


  1. Biga
    04.09.2026 14:18

    Говорить про какие-то форки в наше время...
    "ИИ, сделай мне красиво с гуем и свистоперделками!" - и у тебя собственный проект, идеально под твои требования. Его не нужно с кем-то согласовывать или синхронизовывать. ИИ его развивает для тебя, добавляет нужные фичи, когда понадобится.
    Разве это не так сейчас работает? (немного сарказм)


    1. lexfrei Автор
      04.09.2026 14:18

      Нет, сейчас это не так работает. Сказать "ИИ, сделай мне красиво с гуем и свистоперделками!" можно, но вот получить полноценный продукт из этого не получится.
      Это может быть красивый PoC, но не продукт. Славбогу, до сих пор нужно быть инженером, чтоб делать сложные штуки.
      Да чего далеко ходить, вот с роутером из примера Fable 5 пытался час поднять sfp, хотя я до этого ему сказал, что кейдж пуст. ИИ это продвинутый автокомплит с галлюцинациями, не более.
      И даже если у тебя есть время это вести, то даже довольно "простые" проекты растягиваются на месяцы реальной разработки.
      Я в драфте держал блок про ИИ, но решил, что это очевидно и выкинул. Но, видимо, зря.


      1. ValdikSS
        04.09.2026 14:18

        Глядите, менеджер форков: https://v-it.org/


        1. lexfrei Автор
          04.09.2026 14:18

          Внимательно поглядываю, но не верю, что это может полететь на самом деле. Буду рад, если да.

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


          1. ValdikSS
            04.09.2026 14:18

            Вы и ваш ассистент и есть мейнтейнер.


            1. lexfrei Автор
              04.09.2026 14:18

              Трагично.


  1. ValdikSS
    04.09.2026 14:18

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

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

    Боюсь, здесь вы делаете грубую фактическую ошибку. Открытый (free) код — это про 4 юридические свободы, которые вы упомянули. Такой код можно легально переиспользовать в рамках его лицензии.

    Публичный код (source-available) — это про copyright. Код без лицензии по умолчанию использовать, копировать, распространять нелегально, если не сказано иного. Всё, что на github лежит без лицензии, практически во всех юрисдикциях (и где авторское право основано на copy right’е — праве копирования — которое появилось во время печатных станков, и где оно буквально авторское право, как в России, без возможности отчуждения) использовать нелегально, автор не давал вам такого права.

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

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

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

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

    Вы подняли хорошую тему, которую довольно редко обсуждают, и для обозначения которой нет устоявшихся слов («юридический/технический» и «социальный» — это я выдумал).
    Раньше мне приходилось возмущающейся общественности, как автору технического опенсорса, разъяснять проблематику, разницу, но недавно наткнулся на статью Jeffrey Paul’а, в которой open-source-код сравнивается с подарком! Моё объяснение свелось к: «Не нравится подарок, не подходит? Выкинь и забудь!».

    Это больно, интересно и полезно. И я мог бы просто остановиться на собственном форке — как мне и советуют.
    Так вот: OpenWrt не любит таскать патчи. В общем случае, когда ты приносишь им фикс для ядра, тебя просят хотя бы попытаться отнести его в апстрим
    Второе — бесплатный мейнтейн. После мержа ваш код перестаёт быть вашей проблемой. Когда подсистему рефакторят, ваш драйвер правит тот, кто рефакторит. Когда меняется API — переносят. Драйвер NAND, который я занёс в ядро в июне, будет жить там дольше, чем я буду помнить о его существовании, — и чинить его буду не я.

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

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

    Только вот «общественное благо»

    Хотите поговорить о боге?

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

    По-английски однозначно устоявшегося термина также нет, но чаще всего называется stewarded open source. И Linux, и OpenWRT — stewarded-проекты, не требующие отказа от прав на код (подписи CLA).

    В марте 2024-го я открыл PR в официальный helm-чарт Cloudflare — cloudflare/helm-charts#69, опция отключить дефолтную 404-ю. Два с половиной года. Ноль ответов от мейнтейнеров.

    Давайте пройдёмся по только что выдуманному чек-листу:

    • Проект большой компании

    • Нет явных признаков социального опенсорса

    • Есть contributing-инструкция, гласящая:

    If you are considering filing a pull request, make sure that there’s an issue filed for the work you’d like to do. There might be some discussion required! Filing an issue first will help ensure that the work you put into your pull request will get merged.

    Перевожу с бизнес-языка на токсичный русский:

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

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

    Я рад, что вы редко сталкиваетесь с недопониманием в открытых проектах, и желаю, чтобы его было мало и в дальнейшем!


    1. lexfrei Автор
      04.09.2026 14:18

      (не спорю, просто чуть разворачиваю кто я)

      Мы немного с разных сторон слона трогаем. Помимо хобби (кстати, привет, я тоже пару борд в armbian тащу), последний год я работаю строго в опенсурсе, и прошлые лет 5 старался участвовать. Бывает больно, типа "нести PRs в Nvidia" или "индусы с нейронами PRs нанесли".

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

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

      Не надо обесценивать свои комментарии такими дисклеймерами, они замечательны <3


      1. ValdikSS
        04.09.2026 14:18

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

        Почему бы вам, в случае с Klipper, не заключить контракт с мейнтейнером на поддержку проекта или на разработку его в соответствие с вашим видением? Или не предложить сформировать foundation, включив в него других активных разработчиков? Может, автор был бы этому только рад?

        В статье про Klipper вы используете финансовые термины для оценки работы, но нигде не фигурируют деньги или хоть какой-то другой мотиватор, применимый для бизнес-задач. Статья more or less в моих глазах выглядит как жалоба на то, что вашу работу другие люди не хотят делать бесплатно, а по вашему мнению обязаны.


        1. lexfrei Автор
          04.09.2026 14:18

          Отчасти.

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


          1. ValdikSS
            04.09.2026 14:18

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


            1. lexfrei Автор
              04.09.2026 14:18

              Чаще, напрашиваюсь мейнтейнером. Но да, в чарт cloudflared люди пару раз приносили PRs, например. Мне не обязательно что-то форкать, чтоб показать себя хорошим мейнтейнером


  1. dinar_007
    04.09.2026 14:18

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


  1. tklim
    04.09.2026 14:18

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

    А по теме, ваш пример с openwert, как и ядро линукса или любой другой крупный проект - это полноценная работа. Как в большой компании или корпорации. Там свои правила, свои порядки.

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

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


  1. olartamonov
    04.09.2026 14:18

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

    Во-первых, контракт — это то, с чем соглашаются обе стороны в момент заключения сделки. А то, чего вы хотите, называется «публичная оферта».

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

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

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

    При этом — да, эта проблема в опенсорсе есть. Да, она большая и больная. Нет, у неё нет никакого решения (чиновники ЕС, конечно, однажды могут посчитать иначе, и начать штрафовать на 5000 евро всех авторов проектов, не отвечающих на github issues в срок не более 5 рабочих дней). Придумывать мифический несуществующий контракт и стыдить им авторов проектов — точно не решение.

    Ну, хотя бы потому, что у них нет никаких обязательств вас выслушивать.


    1. ValdikSS
      04.09.2026 14:18

      чиновники ЕС, конечно, однажды могут посчитать иначе, и начать штрафовать на 5000 евро всех авторов проектов, не отвечающих на github issues в срок не более 5 рабочих дней

      Эти ребята довольно прогрессивные: в рамках Cyber Resilience Act заставляют производителя делиться исправлением безопасности с проектом, если его используют, и если исправление у них появилось раньше автора проекта.

      • On the basis of Recital 18 of the Cyber Resilience Act, I do not fall within the scope of the regulation, and cannot be considered as a Manufacturer or an Open source software steward under the Cyber Resilience Act.

      • On the basis of [Recital 15 of the Product Liability Directive][PLD Recital 15], I cannot be held liable for your use of my code.

      • While I don’t have obligations towards you, you may have some towards me: - On the basis of Article 13(6) the Cyber Resilience Act, if you believe you have found a security flaw in this code, you are responsible for reporting it by following the vulnerability disclosure process here: << project link >>. You are also responsible for fixing it within your product and providing the fix upstream.

      https://cra.orcwg.org/faq/maintainers/transparency/

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

      Even in the monetisation scenario, your manufacturer obligations apply only to the monetised version. For example, if you offer both a paid “enterprise” version and a free “community” version, you would be a manufacturer only for the enterprise version.

      https://cra.orcwg.org/faq/maintainers/monetization/


  1. eungenue
    04.09.2026 14:18

    По итогу сегодня кто-то по-старинке пишет код головой за звездочки в опенсорс, а кто-то с этого продает подписку чатгпт как за своё :/


  1. Newbilius
    04.09.2026 14:18

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


    1. petropavel
      04.09.2026 14:18

      Вообще-то в первой вроде бы вполне ясно написано, что не бесплатно.