<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Git</title>
    <description>Git — распределённая система управления версиями (VCS), активно используемая программистами в IT-проектах для отслеживания и ведения истории изменения файлов.</description>
    <link>https://tproger.ru/tag/git</link>
    <atom:link href="https://tproger.ru/tag/git/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Fri, 25 Sep 2026 19:26:12 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Git</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Вышел flatpak-builder 1.4.11 с исправлениями безопасности</title>
      <link>https://tproger.ru/news/vywel-flatpak-builder-1-4-11-s-ispravleniyami-bezopasnosti</link>
      <comments>https://tproger.ru/news/vywel-flatpak-builder-1-4-11-s-ispravleniyami-bezopasnosti?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/vywel-flatpak-builder-1-4-11-s-ispravleniyami-bezopasnosti</guid>
      <description><![CDATA[<p>Сборщик Linux-приложений Flatpak Builder обновился до версии 1.4.11. Обновление отключает Git-хуки при применении патчей и устраняет выход источников за пределы base_dir в режиме песочницы.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/vywel-flatpak-builder-1-4-11-s-ispravleniyami-bezopasnosti">Вышел flatpak-builder 1.4.11 с исправлениями безопасности</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 13 Sep 2026 13:25:04 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Что произошло</h2><p>Flatpak Builder — инструмент для разработчиков и сопровождающих Linux-приложений: он собирает их в пакеты формата Flatpak. Версия flatpak-builder 1.4.11 вышла 12 сентября. В ней полностью отключили Git-хуки при применении патчей. Изменение связано с уязвимостью CVE-2026-86320. Также разработчики исправили проблему GHSA-484h-v688-jq5j, из-за которой источник мог выйти за пределы base_dir в режиме песочницы.</p><p>Кроме того, flatpak-builder теперь раньше прерывает обработку некорректных контрольных сумм для архивов и файлов, проверяет наличие URL при разборе источников bzr и svn и пропускает уже перенесённые записи при миграции локалей.</p><h2>Что делать</h2><p>Если используется более ранний выпуск, стоит перейти на 1.4.11. В заметках к релизу не указаны затронутые диапазоны версий или дополнительные меры защиты, поэтому ориентиром остаётся установка исправленного выпуска.</p><h2>Источники</h2><ul><li><a href="https://github.com/flatpak/flatpak-builder/releases/tag/1.4.11">Release 1.4.11 · flatpak/flatpak-builder · GitHub</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Jujutsu 0.45 научился сам сводить расходящиеся коммиты командой jj converge</title>
      <link>https://tproger.ru/news/jujutsu-0-45-nauchilsya-sam-svodit-rashodyashhiesya-kommity-komandoj</link>
      <comments>https://tproger.ru/news/jujutsu-0-45-nauchilsya-sam-svodit-rashodyashhiesya-kommity-komandoj?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/jujutsu-0-45-nauchilsya-sam-svodit-rashodyashhiesya-kommity-komandoj</guid>
      <description><![CDATA[<p>В jj 0.45.0 появилась команда jj converge для автоматического сведения divergent-коммитов, изменился выбор конфига при --user и импорт detached HEAD из Git. Что проверить после обновления.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/jujutsu-0-45-nauchilsya-sam-svodit-rashodyashhiesya-kommity-komandoj">Jujutsu 0.45 научился сам сводить расходящиеся коммиты командой jj converge</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 03 Sep 2026 09:33:30 GMT</pubDate>
      <content:encoded><![CDATA[<p>Проект Jujutsu 3 сентября в 07:47 мск <a href="https://github.com/jj-vcs/jj/releases/tag/v0.45.0">выпустил</a> версию 0.45.0 своей системы контроля версий jj, которая работает поверх обычного Git-репозитория. Главное в релизе новая команда jj converge: она находит расходящиеся версии одного изменения и заменяет их одним коммитом, сама подбирая решение и спрашивая пользователя только там, где эвристики не справились.</p><p>Для тех, кто уже пользуется jj, это закрывает самую неприятную бытовую проблему инструмента, а два ломающих изменения в том же релизе стоит проверить сразу после обновления: команды jj config с флагом --user больше не спрашивают, какой файл править, а jj git import перестал подтягивать коммиты из отсоединённого HEAD в репозиториях без совмещения с Git. Предыдущая версия 0.44.0 выходила 6 августа, релизы у проекта идут примерно раз в месяц.</p><ul><li>jj converge заменяет две и больше видимых ревизии одного change ID одним коммитом; потомки перебазируются на решение, локальные закладки переезжают сами.</li><li>Если эвристики не уверены, команда задаёт вопросы: слить описания, выбрать родителей, редко выбрать автора; в режиме --no-interactive операция прерывается, если нужен вопрос пользователю.</li><li>Ломающее: jj config edit/set/unset --user теперь правит первый загруженный пользовательский конфиг, для точного выбора файла добавлен --file ПУТЬ.</li><li>Ломающее: jj git import в неколоцированных репозиториях больше не импортирует коммиты с отсоединённого Git HEAD.</li><li>Git HEAD теперь хранится отдельно для каждого worktree, существующие репозитории мигрируют автоматически; исправлен баг с duplicateEntries в git fsck после git add.</li></ul><h2>Откуда в jj берутся расходящиеся коммиты</h2><p>В jj у каждого изменения есть постоянный change ID, который переживает перезапись коммита: можно поправить старый коммит в середине стека, и потомки перебазируются автоматически. Расхождение, или divergence, возникает, когда одно и то же изменение оказалось переписано дважды по разным веткам истории операций. Типичный сценарий: правка в двух рабочих пространствах, откат через jj undo после того, как часть работы уже ушла дальше, или неудачный конфликт при синхронизации с удалённым Git-репозиторием. В логе это выглядит как два коммита с одинаковым change ID, и до 0.45 их приходилось сводить руками через jj abandon, jj squash и jj rebase.</p><h2>Что делает jj converge на самом деле</h2><p>По <a href="https://github.com/jj-vcs/jj/blob/v0.45.0/cli/src/commands/converge.rs">описанию команды</a> в исходниках, jj converge берёт ревизии из аргумента --revisions или из настройки revsets.converge, группирует их по change ID и считает расходящимися те группы, где ревизий больше одной. Если расходящихся изменений несколько, команда спросит, какое сводить. Дальше она применяет эвристики, чтобы собрать новую ревизию, а если те дали неоднозначный результат, задаёт вопросы: объединить ли описания, каких родителей выбрать и, в редких случаях, кого считать автором.</p><p>Когда решение найдено, новая ревизия заменяет расходящиеся, потомки перебазируются на неё, а локальные закладки, указывавшие на любую из старых версий, переезжают на новую. Два ограничения авторы оговаривают прямо. Во-первых, сводятся только ревизии, попавшие в revset: если у того же change ID есть видимые версии вне выборки, расхождение уменьшится, но не исчезнет. Во-вторых, в результате могут появиться файловые конфликты, даже если до этого их не было. Проверить, что именно сделала команда, можно через jj op show -p, посмотреть историю изменения через jj evolog, а откатить всё одним jj undo.</p><p>Режим --no-interactive нужен для скриптов и хуков: если без вопроса не обойтись, команда не зависнет в ожидании ввода, а прервётся с предупреждением.</p><h2>Что сломается после обновления</h2><p>Первое ломающее изменение касается конфигов. Раньше jj config edit --user, set --user и unset --user при нескольких пользовательских файлах, например ~/.config/jj/config.toml плюс каталог conf.d/, спрашивали, какой файл править. Теперь они молча берут первый загруженный. Если у вас конфиг разложен по нескольким файлам, нужный указывается явно:</p><p>Второе касается репозиториев, где jj живёт рядом с Git, но не в колоцированном режиме, то есть .jj и .git не делят один рабочий каталог. jj git import в них больше не импортирует коммиты с отсоединённого Git HEAD. Если рабочий процесс опирался на то, что jj подхватит коммит, сделанный в Git в состоянии detached HEAD, теперь такой коммит нужно закрепить веткой или тегом на стороне Git.</p><p>Внутреннее изменение, которое тоже стоит знать: состояние Git HEAD теперь хранится отдельно для каждого worktree. Это подготовка к поддержке нескольких Git worktree в колоцированных репозиториях, когда у каждого рабочего пространства jj свой HEAD. Существующие репозитории мигрируют автоматически при первом запуске новой версии.</p><h2>Исправления, которые заметят те, кто уже обжигался</h2><ul><li>В колоцированных репозиториях git add после команды jj больше не оставляет в индексе устаревший cache-tree, из-за которого git fsck ругался на duplicateEntries. Уже испорченные репозитории исправление не лечит.</li><li>Ctrl+C в пейджере less теперь выходит чисто: во флаги по умолчанию добавили -K, раньше терминал мог остаться в raw-режиме с мусором из escape-последовательностей.</li><li>Сторона конфликта, оканчивающаяся на символ возврата каретки, больше не теряет этот байт при повторном разборе материализованного конфликта.</li><li>jj run останавливается на первой ревизии, где процесс завершился с ненулевым кодом, вместо того чтобы идти дальше.</li><li>Набор immutable_heads() по умолчанию теперь включает untracked_remote_tags(); jj bisect предупреждает, когда из-за пропусков не может однозначно назвать первую плохую ревизию; починен краш jj log на скрытых ревизиях с revset log-graph-prioritize.</li></ul><h2>Как обновиться</h2><p>Готовые сборки для Windows, macOS и Linux лежат на странице релиза, вариант с musl должен работать на любом дистрибутиве. По <a href="https://docs.jj-vcs.dev/v0.45.0/install-and-setup/">документации</a> установить последний релиз можно так:</p><p>Кому обновление ничего не изменит: тем, кто держит jj в одном файле конфига и работает только в колоцированных репозиториях. Им достанется jj converge и исправления, а ломающие изменения не затронут. Следующий сигнал, за которым стоит следить, это планируемая поддержка нескольких Git worktree, под которую в 0.45 подготовили хранение HEAD.</p><p>Источники: <a href="https://github.com/jj-vcs/jj/releases/tag/v0.45.0">Релиз jj v0.45.0 на GitHub</a>, <a href="https://docs.jj-vcs.dev/v0.45.0/install-and-setup/">Документация: установка и настройка jj 0.45</a>, <a href="https://github.com/jj-vcs/jj/blob/v0.45.0/cli/src/commands/converge.rs">Исходник команды converge (описание в cli/src/commands/converge.rs)</a></p><p>Изображение на обложке: Логотип: J. Jennings, CC BY 4.0</p>]]></content:encoded>
    </item>
    <item>
      <title>DoltLite вышел в бету: SQLite с ветками и merge, но запись дороже</title>
      <link>https://tproger.ru/news/doltlite-vywel-v-betu-sqlite-s-vetkami-i-merge-no-zapis-dorozh</link>
      <comments>https://tproger.ru/news/doltlite-vywel-v-betu-sqlite-s-vetkami-i-merge-no-zapis-dorozh?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/doltlite-vywel-v-betu-sqlite-s-vetkami-i-merge-no-zapis-dorozh</guid>
      <description><![CDATA[<p>DoltHub объявила бету DoltLite 0.50.0, форка SQLite с Prolly Tree вместо B-tree: ветки, diff, merge, push и pull для локальной базы. Совместимость с тестами SQLite 99,46%, запись медленнее до 3,1 раза.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/doltlite-vywel-v-betu-sqlite-s-vetkami-i-merge-no-zapis-dorozh">DoltLite вышел в бету: SQLite с ветками и merge, но запись дороже</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 02 Sep 2026 01:33:06 GMT</pubDate>
      <content:encoded><![CDATA[<p>Компания DoltHub 31 августа <a href="https://www.dolthub.com/blog/2026-08-31-doltlite-beta/">объявила</a>, что DoltLite, её форк SQLite с Git-подобным контролем версий, достиг стадии Beta и получил версию 0.50.0. Для разработчика это значит: формат хранения объявлен стабильным, и базу с ветками, diff и merge теперь можно пробовать в настоящих проектах, а не только в экспериментах. Цена версионирования тоже названа: мелкие записи в несколько раз медленнее SQLite.</p><p>DoltLite запустили 25 марта 2026 года как замену SQLite, у которой вместо B-tree под капотом content-addressed Prolly Tree. Всё остальное, по описанию основателя DoltHub Тима Сена, от SQLite: парсер SQL, анализатор, файловый слой и тестовый harness. До беты ушло около 2000 pull request и пять месяцев.</p><ul><li>DoltLite 0.50.0 объявлен бетой: стабильный формат хранения, SQL-совместимость и полный набор операций контроля версий.</li><li>Поддерживаются branch, merge, diff, rebase, cherry-pick, reset, а также push, pull, clone и fetch на свой remote или DoltHub.</li><li>Из 892 277 TCL-тестов SQLite проходят 99,46%; sqllogictest на 5,8 млн запросов проходит полностью; известно 4809 расхождений.</li><li>В памяти чтение медленнее SQLite на 10%, запись на 60%; для файловых баз чтение на уровне SQLite, пакетная запись медленнее на 10%.</li><li>Мелкие autocommit-записи медленнее в 3,1 раза: около 400 мкс против 125 мкс у SQLite.</li></ul><h2>Что «бета» означает у DoltHub</h2><p>Компания перечисляет четыре условия. Стабильный формат хранения: до беты он менялся 12 раз, а текущий вариант продержался 57 релизов, больше трёх месяцев, и для будущих несовместимых изменений обещан путь миграции. SQL-совместимость: DoltLite проходит 100% sqllogictest, это 5,8 млн запросов, и 99,46% из 892 277 TCL-тестов самого SQLite. Полный контроль версий: ветки, слияния, diff, rebase, cherry-pick, reset и удалённые операции. И производительность, пригодная для production, с оговорками ниже.</p><p>Оставшиеся 4809 расхождений с SQLite DoltHub объясняет архитектурой: отказ от rowid, chunk вместо page и отсутствие WAL и journal-файлов рядом с базой. Если код полагается на эти детали SQLite, миграция не будет прозрачной; проверить стоит именно их.</p><h2>Сколько стоит версионирование</h2><p>Замеры приводит сам вендор. Для базы в памяти чтение медленнее SQLite примерно на 10%, запись примерно на 60%. Для файловой базы чтение на уровне SQLite, пакетная запись медленнее примерно на 10%. Хуже всего мелким autocommit-транзакциям: каждая такая запись занимает около 400 мкс против 125 мкс у SQLite, то есть в 3,1 раза дольше. Причина в природе Prolly Tree: каждое изменение порождает новые chunk с хешами, и на одиночной вставке эта работа не амортизируется.</p><p>На практике это значит, что DoltLite подходит для сценариев, где данные меняются пакетами и важна история: конфигурации, справочники, наборы данных для ML, локальные базы в приложениях, где нужен откат и сравнение версий. Для очереди с тысячами мелких вставок в секунду SQLite по-прежнему быстрее, и вендор этого не скрывает.</p><h2>Что можно сделать уже сегодня</h2><p>Рабочий цикл похож на Git: создать ветку, изменить данные, посмотреть diff, слить. Удалённые операции push, pull, clone и fetch работают с собственным remote или с DoltHub. 7 августа DoltHub добавила поддержку DoltLite в Dolt Workbench, свой графический клиент, где ветвление, diff и merge доступны из интерфейса.</p><p>Сборки, по данным репозитория, есть для Linux, macOS, Windows, Python, Node.js, Rust, Android и WebAssembly. Лицензия в анонсе беты не указана, и перед использованием в коммерческом продукте её стоит уточнить в репозитории.</p><p>Релиз 0.50.0 не содержит изменений кода относительно 0.11.57: номер версии подняли, чтобы обозначить бету. Если вы уже на 0.11.57, обновляться ради кода не нужно.</p><h2>Контекст</h2><p>DoltHub с 2018 года развивает Dolt, версионируемую базу, совместимую с MySQL. DoltLite переносит ту же идею на встраиваемый движок: Prolly Tree даёт дешёвое сравнение версий по хешам и структурное слияние, а SQLite даёт зрелый SQL-слой. По нашей оценке, главный практический вопрос беты не в фичах, а в том, насколько быстро проект закроет разрыв в мелких записях: именно там пройдёт граница между «база для датасетов» и «замена SQLite в приложении».</p><p>Сроков выхода стабильной версии DoltHub не называет; редакция проверит, изменится ли производительность записи в следующих релизах.</p><p>Источники: <a href="https://www.dolthub.com/blog/2026-08-31-doltlite-beta/">Блог DoltHub: DoltLite Beta</a>, <a href="https://github.com/dolthub/doltlite/releases/tag/v0.50.0">Релиз v0.50.0 на GitHub</a></p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub CLI 2.99 прикладывает скриншоты и видео к issue из терминала</title>
      <link>https://tproger.ru/news/github-cli-2-99-prikladyvaet-skrinwoty-i-video-k-issue-iz-termin</link>
      <comments>https://tproger.ru/news/github-cli-2-99-prikladyvaet-skrinwoty-i-video-k-issue-iz-termin?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-cli-2-99-prikladyvaet-skrinwoty-i-video-k-issue-iz-termin</guid>
      <description><![CDATA[<p>В GitHub CLI 2.99.0 появился флаг --attach: картинки и видео загружаются в issue, pull request и комментарии прямо из терминала. Лимиты, форматы, требования к токену и что не работает на Enterprise Server.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-cli-2-99-prikladyvaet-skrinwoty-i-video-k-issue-iz-termin">GitHub CLI 2.99 прикладывает скриншоты и видео к issue из терминала</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Инструменты командной строки]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 02 Sep 2026 01:32:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>GitHub 1 сентября <a href="https://github.blog/changelog/2026-09-01-github-cli-media-in-issues-pull-requests-and-comments/">объявил</a>, что в GitHub CLI появился флаг --attach: он загружает локальные изображения и видео в issue, pull request или комментарий. Раньше терминальный клиент умел работать только с текстом, а скриншот или запись экрана приходилось тащить через браузер. Функция доступна всем пользователям GitHub на всех тарифах после обновления до версии 2.99.0.</p><p>Для тех, кто пишет багрепорты из скриптов, собирает отчёты в CI или просто не хочет переключаться в браузер ради одной картинки, это закрывает давний разрыв между «вот команда, которая падает» и «вот как это выглядит». Единственное серьёзное исключение: GitHub Enterprise Server в этом релизе не поддерживается.</p><ul><li>Флаг --attach работает в gh issue create, edit, comment и в gh pr create, edit, comment; его можно повторять несколько раз.</li><li>Форматы: PNG, JPEG, GIF, WebP, SVG для картинок и MP4, MOV, WebM для видео.</li><li>Лимит на изображение и GIF 10 МБ; видео до 10 МБ на бесплатном плане и до 100 МБ на платных.</li><li>Нужен OAuth-токен от gh auth login или classic personal access token и право записи в репозиторий.</li><li>GitHub Enterprise Server не поддерживается; нужна версия gh 2.99.0.</li></ul><h2>Как это выглядит в командной строке</h2><p>Минимальный пример из changelog: приложить скриншот к комментарию в issue.</p><p>Флаг повторяемый, поэтому к одному issue можно приложить сразу несколько файлов, указав --attach для каждого. Alt-текст задаётся после пути через решётку: --attach './login.png#The login error state'. Это тот же alt, который потом увидят читатели со скринридером, так что писать его стоит осмысленно.</p><p>Самая полезная деталь спрятана в обработке Markdown. Если в тексте issue или комментария уже стоит локальная ссылка вида ![alt](./login.png), CLI перепишет её на адрес загруженного файла. Вложения, на которые в тексте ссылок нет, добавляются в конец Markdown. Значит, можно писать описание бага в редакторе с относительными путями к картинкам, а потом одной командой отправить и текст, и файлы.</p><h2>Ограничения, о которых стоит знать заранее</h2><p>Для загрузки нужен либо OAuth-токен, полученный через gh auth login, либо classic personal access token; другие типы токенов в changelog не упомянуты, и это стоит учитывать в CI. Кроме того, требуется право записи в репозиторий: приложить файл к чужому issue в проекте, где вы не участник, не получится, даже если оставлять комментарии там можно.</p><p>Лимиты размеров: 10 МБ для изображений и GIF, для видео 10 МБ на Free и 100 МБ на платных планах. GitHub Enterprise Server новую возможность не получил; сроки для самостоятельно развёрнутых инсталляций в публикации не названы.</p><p>Что ещё не сказано: как ведёт себя команда при превышении лимита, поддерживает ли она загрузку по URL вместо локального файла и когда флаг доберётся до gh release. Судя по тексту changelog, речь только об issue, pull request и комментариях.</p><h2>Где это пригодится</h2><ul><li>Тестовые пайплайны: упавший end-to-end тест прикладывает скриншот или запись браузера к автоматически созданному issue.</li><li>Ревью интерфейсов: gh pr comment --attach с записью экрана вместо описания «нажмите сюда, потом сюда».</li><li>Скрипты отчётов: график из matplotlib или диаграмма сборки уходит в комментарий к pull request без промежуточного хостинга.</li></ul><p>Обновиться можно штатным способом: через менеджер пакетов, которым gh ставился, или скачав релиз 2.99.0 с GitHub.</p><p>Редакция проверит, появится ли поддержка Enterprise Server в следующих релизах gh.</p><p>Источник: <a href="https://github.blog/changelog/2026-09-01-github-cli-media-in-issues-pull-requests-and-comments/">Changelog GitHub: GitHub CLI media in issues, pull requests, and comments</a></p><p>Изображение на обложке: GitHub</p>]]></content:encoded>
    </item>
    <item>
      <title>Ваши open source-контрибьюторы теперь ИИ-first. Как не утонуть в потоке агентских пулреквестов</title>
      <link>https://tproger.ru/articles/vawi-kontribyutory-teper-ai-first-kak-ne-utonut-v-potoke-agen</link>
      <comments>https://tproger.ru/articles/vawi-kontribyutory-teper-ai-first-kak-ne-utonut-v-potoke-agen?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/vawi-kontribyutory-teper-ai-first-kak-ne-utonut-v-potoke-agen</guid>
      <description><![CDATA[<p>Агенты генерируют пулреквесты в open source. Разбираем опыт AutoGPT: как ставить ворота, писать AGENTS.md и не тратить команду на ревью слабых PR.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/vawi-kontribyutory-teper-ai-first-kak-ne-utonut-v-potoke-agen">Ваши open source-контрибьюторы теперь ИИ-first. Как не утонуть в потоке агентских пулреквестов</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Организация разработки]]></category>
      <category><![CDATA[Методологии разработки]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 19 Aug 2026 07:01:11 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если в очереди на ревью вашего open source-проекта всё чаще оказываются пулреквесты, написанные не человеком, а агентом, — вы не одни. Чтобы не утонуть в этом потоке, мейнтенеру нужно перенести правила рядом с кодом и настроить автоматические ворота: шаблон PR, CI, требования к тестам и лицензионное соглашение участника.</p><p>В AutoGPT, где на момент интервью у репозитория было свыше 180 тысяч звёзд и 150 открытых PR, большая часть этих PR создана агентами: Copilot, OpenClaw, собственными инструментами команды и сторонними ботами. Большинство мейнтенеров реагируют просто: закрыть дверь, отключить пулреквесты, не тратить силы на чужой LLM-вывод. Но у Николаса Тиндла, одного из основателей ИИ-инженерии в AutoGPT, другой взгляд: «По сути, кто-то другой платит за ваши вычислительные ресурсы. Если контрибьютор хочет потратить свои токены на улучшение вашего проекта — пусть тратит. Главное, сделать так, чтобы единственный путь внутрь проходил через ваши правила.»</p><p>ИИ-first контрибьютор — это разработчик, который отдаёт написание кода, тестов или документации генеративной модели, либо самоходный агент, который клонирует репозиторий, ищет issue, пишет код и открывает PR. Для мейнтенера результат одинаков: в репозиторий приходит поток кода, который часто не учитывает контекст проекта и требует ревью.</p><p>Агенты не ищут документацию сами — они читают то, что лежит рядом с кодом. AGENTS.md и CLAUDE.md в нужных директориях работают лучше, чем вики.</p><p>Пропускные ворота должны быть автоматическими и однозначными: шаблон PR, тест-план, CI как стена, CLA как детектор человека.</p><p>Не все ворота стоит оставлять включёнными: автоматические комментарии об ошибках CI быстро превращаются в шум.</p><p>Плохой AGENTS.md хуже, чем его отсутствие: избыточные инструкции засоряют контекст и ломают поведение агентов.</p><p>Мейнтенер всё ещё решает, что принимать: закрыть PR и переписать самому — тоже валидный выбор.</p><h2>Проблема не в документации, а в её обнаружении</h2><p>Первое, что пробовала сделать AutoGPT, — улучшить CONTRIBUTING.md, написать подробную вики и обновить гайды. Это не сработало. Дело в том, что агенты не ходят по ссылкам и не ищут документацию в разделах репозитория. Они смотрят на то, что находится в текущей директории и на один-два уровня выше. Если инструкция не лежит там, где агент работает, для него её не существует.</p><p>Сначала команда добавила файлы CLAUDE.md, потому что Claude открывал пулреквесты без достаточного контекста о репозитории. Потом выяснилось, что Copilot и Codex эти файлы игнорируют — они не Claude. Решением стал централизованный AGENTS.md, на который указывают все специфичные для модели файлы.</p><p>Важный нюанс: AGENTS.md действует внутри директории. Если агент работает в backend/, он видит правила для бэкенда. Если динамически загружается навык, связанный с фронтендом, агент может не знать, в какой директории искать инструкции — и навык сам должен ему подсказать путь. Поэтому в AutoGPT файл AGENTS.md лежит рядом с кодом, который он регулирует.</p><p><b>Навык — что это?</b><br />В терминологии агентских инструкций навык — это файл с описанием, по которому агент решает, когда загружать полный набор правил. Агент сканирует описания заранее и подключает нужный навык, когда задача совпадает. Например: «напиши Storybook-тест, если компонент лежит в этих папках».</p><p>Фронтенд-инженер AutoGPT устал от одного и того же класса сломанных PR в open source-проекте и оформил гайд как навык. Теперь каждый агент, который касается репозитория, видит триггер и выполняет правило. Бэкенд делает то же самое: не набрал 80% покрытия — PR не пройдёт.</p><h2>Ворота для ИИ-контрибьюторов в open source</h2><p>AutoGPT выстроила несколько механизмов, которые сдерживают поток низкокачественных пулреквестов и заставляют агентов вести себя предсказуемо.</p><h3>Шаблон пулреквеста как пропускной пункт</h3><p>В шаблоне PR прямо написано: PR, не соответствующий шаблону, закрывается автоматически и без колебаний. Команда даже построила бота, который это делает. Но запускать его не понадобилось — само правило изменило поведение агентов. Агенты стали заполнять шаблон. А вот люди иногда его игнорировали, и это Тиндл считает полезным сигналом: «Если вы не следуете шаблону, вы, скорее всего, человек, и я отнесусь к вам мягче.»</p><h3>Тест-план, который запускает код</h3><p>В шаблоне есть раздел тест-плана, и его формулировка незаметно подсказывает агенту протестировать пулреквест. Эта фраза активирует навык test PR: агент устанавливает браузер, разворачивает приложение и проверяет изменение. Агент пришёл поставить галочку, а в итоге запустил код. После этого сломанные PR стали редкостью. Осталась другая проблема — PR, которые работают, но не вписываются в дорожную карту.</p><h3>CI — стена, а не рекомендация</h3><p>Codecov и другие проверки настроены как required checks. Агент открывает PR, через несколько минут видит, что мёрж заблокирован, загружает навык с тестами и добивается покрытия. Никто не просил — инфраструктура сама направила агента.</p><h3>CLA (Contributor License Agreement) как детектор человека</h3><p>AutoGPT использует двойную лицензию, но Тиндл советует лицензионное соглашение участника (Contributor License Agreement, CLA) любому проекту, даже MIT. Подписание требует браузера и OAuth-потока GitHub на отдельном домене. Сегодня агенты с этим справляются плохо — и это хорошо, потому что большинство мейнтенеров не хотят, чтобы агент ходил в GitHub от их имени. Если CLA не подписан в течение недели, PR закрывается с комментарием «подпишите CLA и переоткройте».</p><h3>SHA коммита перед закрытием замечания</h3><p>Часть агентов закрывает все треды ревью, не исправляя код. В AutoGPT есть навык pr-address, который описывает допустимую последовательность: исправить, закоммитить, запушить, ответить, потом разрешить тред. Ответ должен содержать полный SHA коммита, полученный через git rev-parse HEAD, чтобы агент не подсунул старый хеш. Навык явно называет антипаттерны: «Acknowledged» — не исправление, и ссылка на коммит, который не трогает указанную строку, тоже не считается.</p><h2>Ворота, от которых пришлось отказаться</h2><p>Когда CI падает, AutoGPT изначально запускала агента, который читал лог и писал комментарий, что сломалось. Первая версия использовала Claude Code внутри GitHub Actions с аутентификацией в CI — лишняя широкая учётная запись. Потом перешли на Copilot внутри рабочего процесса: тот же результат, но без лишних кредов.</p><p>А потом выключили именно автоматические комментарии об ошибках CI. Прогоны в AutoGPT падают часто, и бот, который целыми днями описывает каждый падший прогон, создаёт не меньше шума, сколько и сами ошибки. Урок: оставляйте то, что снижает нагрузку на мейнтенера, и выключайте то, что превращается в фоновый шум.</p><h2>Четыре ловушки, которые стоит записать</h2><ul><li><b>Плохой AGENTS.md хуже, чем его отсутствие.</b> В AutoGPT сначала разбросали файлы повсюду и засорили контекст. Если поведение агентов ухудшилось — перечитайте, что вы написали.</li><li><b>GraphQL API GitHub быстро исчерпывает лимит запросов.</b> Если каждый инструмент в команде ходит в CLI как отдельный пользователь, лимит закончится. Создайте GitHub App и аутентифицируйте CLI через неё.</li><li><b>Сложное ревью стоит реальных денег.</b> У AutoGPT PR проходит через клон ветки, восемь агентов с разными ролями, запуск стека и скриншоты. Круто, но дорого. Сейчас эту процедуру запускают только для совсем маленьких или крупных PR.</li><li><b>Проверяйте авторизованные приложения.</b> Каждый протестированный инструмент оставляет OAuth-разрешение. Если перестали использовать приложение — удалите его из настроек GitHub.</li></ul><h2>Не всё в open source решается воротами</h2><p>Тиндл подчёркивает два тезиса, которые не связаны с инструментами. Первый: вы не обязаны принимать каждый пулреквест. Мёржить чужой LLM-вывод — асимметричная сделка: вы будете поддерживать этот код вечно. Закрыть PR и переписать решение самому — валидный выбор.</p><p>GitHub даёт мейнтенерам ручки: можно отключить пулреквесты целиком, ограничить создание issue только участникам с правами collaborator или требовать предварительного обсуждения. Если хотите — вообще закройте приём внешнего кода, как это сделали в SQLite: они принимают только баг-репорты. У вашего проекта тоже может быть своя граница.</p><p>Второй тезис: когда вы закрываете PR, но переписываете его идею сами, добавьте автора как соавтора, если это уместно. В AutoGPT 800 контрибьюторов, и один дополнительный соавтор ничего не стоит. Для большинства людей важно, что их проблему заметили и исправили.</p><h2>Выводы</h2><p>Open source развивался, делая сотрудничество явным: лицензии формализовали разрешения, issue сделали работу видимой, пулреквесты превратили ревью в общую практику. Инструкции для агентов в репозитории — следующий шаг в этом направлении. Правильная форма ещё не устоялась: у AutoGPT уже третья версия AGENTS.md, и она появилась потому, что команда сначала развёртывала плохие версии и смотрела, что с ними делают агенты.</p><p>Тиндл советует мейнтенерам записываться в программу обратной связи GitHub — maintainers.github.com:</p><blockquote>You've got to go there. You've got to sign up. It gets you all the connections you want at GitHub. That's where I learned about all this stuff, and where I share it.</blockquote><p>Мейнтенер всё ещё решает, что принимать, и задаёт планку. Разница лишь в том, что всё больше этого решения можно вынести рядом с кодом — туда, где уже находятся ваши контрибьюторы и их агенты.</p><p>Если тема интересна, загляните в разделы tproger: <a href="https://tproger.ru/tag/open-source">open source</a>, <a href="https://tproger.ru/tag/github">GitHub</a> и <a href="https://tproger.ru/tag/ai">искусственный интеллект</a>.</p><p><b>Источник:</b> <a href="https://github.blog/open-source/maintainers/your-contributors-are-ai-first-now-is-your-project/">GitHub Blog — Your contributors are AI-first now. Is your project?</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Своя self-hosted двухсерверная VPN-архитектура. Подробный путь разработки и ошибки, с которыми вы можете столкнуться</title>
      <link>https://tproger.ru/articles/svoya-self-hosted-dvuhservernaya-vpn-arhitektura-podrobnyj-put-r</link>
      <comments>https://tproger.ru/articles/svoya-self-hosted-dvuhservernaya-vpn-arhitektura-podrobnyj-put-r?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Роман Фролов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/svoya-self-hosted-dvuhservernaya-vpn-arhitektura-podrobnyj-put-r</guid>
      <description><![CDATA[<p>Проект представляет из себя быстрый способ воссоздать архитектуру состоящую из 2 серверов (локальный + удаленный) с определенными сервисами, которые решают специфические задачи. Проект сделан прежде всего для меня, а также для людей которые хотят свой готовый self-hosted сервер из коробки с полной системой обслуживания</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/svoya-self-hosted-dvuhservernaya-vpn-arhitektura-podrobnyj-put-r">Своя self-hosted двухсерверная VPN-архитектура. Подробный путь разработки и ошибки, с которыми вы можете столкнуться</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[unix]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Музыка]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[DIY]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[VPN]]></category>
      <category><![CDATA[Telegram]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[NFT]]></category>
      <category><![CDATA[Машин]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[DeFi]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[VPS]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 26 Jul 2026 15:46:26 GMT</pubDate>
      <content:encoded><![CDATA[<p>Всё
 началось с того, что меня перестал устраивать мой подход к 
развертыванию личных сервисов. Я решил переписать всё с нуля. К тому же 
это был отличный повод получить новые навыки и попробовать инструменты, 
до которых давно не доходили руки.</p><p>Арендовать мощные VPS под 
ресурсоемкие задачи в текущих реалиях выходит неоправданно дорого. При 
этом дома у меня уже был выделенный неттоп (мини-ПК) с 16 ГБ оперативной
 памяти на базе энергоэффективного процессора Intel N95.</p><p>Пройдя 
путь от простых Bash-скриптов и сторонних туннелей до полностью 
автоматизированной инфраструктуры, я создал проект ServeHub-2. В этой 
статье я подробно разберу, как эволюционировала сеть проекта, почему 
декларативный подход победил императивный и с какими неочевидными багами
 пришлось столкнуться в процессе автоматизации.</p><h2>История настройки сетевой архитектуры</h2><h3>Использование Tuna</h3><p>В
 самом начале проекта я еще не думал о VPN как о способе пробития NAT и 
основе, на которой будет строиться вся система. Первое, к чему я пришел —
 сервис Tuna. Если кратко, это аналог Cloudflare Tunnel за условные 300 
рублей. У него очень приятный веб-интерфейс и невероятно простая 
настройка. Однако для полноценной независимой архитектуры он не подошел 
по двум причинам:</p><ul><li>Сервера Tuna находятся вне контроля пользователя.</li><li>На удаленном сервере нельзя развернуть свои сопутствующие сервисы.</li></ul><p>В целом сервис действительно удобный, но для моих задач он оказался слишком ограничивающим.</p><p>Вот
 пример конфига для tuna (все максимально просто, создаем контейнеры для
 ssh туннеля, чтобы был доступ ssh, а также основной http туннель с 
привязкой к nginx или любому другому прокси если такой есть):</p><h3>В поисках гибкости: тесты Pangolin и переход к FRP</h3><p>После Tuna я решил двигаться в сторону собственного контроля и попробовал Pangolin.
 Однако решение быстро отвалилось: для дешёвого сервера оно оказалось 
слишком «тяжёлым» и избыточным. Главные минусы — ощутимый оверхед по 
ресурсам и лишний слой принудительной веб-аутентификации перед самими 
сервисами. Это ломало нормальное взаимодействие с родными мобильными 
клиентами (вроде Element для Matrix или Bitwarden для паролей), где 
повторная авторизация в браузере просто не нужна.</p><p>На смену пришел FRP (Fast Reverse Proxy).
 Он выполнял ту же функцию проброса, но хостил я его уже на собственном 
арендованном VPS в режиме Layer 4 (TCP). Это дало абсолютную гибкость: 
внешний VPS не заглядывал внутрь пакетов и ничего не расшифровывал, а 
просто пересылал сырой поток домой. Кроме того, это отлично 
оптимизировало расходы: вместо 300 рублей за Tuna и ещё 300 рублей за 
отдельный VPN, я стал платить всего 500 рублей за один стойкий VPS, 
который мог настраивать как хочу. (к тому же можно было обойтись даже 
дешевле, так как VPS с 4 гб оперативки загружен всего лишь на 40%, 
процессор всего на 20%-40%)</p><p>FRP состоит из 2 конфигурационных 
файлов (один на удаленном сервере frp server, другой на локальном frp 
client), все также довольно просто, однако его можно использовать на 
разных слоях. У меня он брал трафик за стандартный TCP и передавал его 
на локальный сервер.</p><p>Также доп. фишка в том что основная 
конфигурация происходит именно в frpc, который, в свою очередь, передает
 часть настроек на frp на удаленном сервере.</p><p>frpc.toml:</p><p>frps.toml:</p><h3>Полноценный переезд на WireGuard (AmneziaWG) и 8 часов отладки</h3><p>Со временем архитектура эволюционировала в сторону полноценной VPN-сети на базе WireGuard, а точнее — его модификации AmneziaWG. Причин для этого шага было несколько:</p><ul><li>Безопасность: FRP всё же открывал внутренние ресурсы в публичный интернет, оставляя их доступными для сканеров портов.</li><li>Удобство маршрутизации:
 Все участники сети стали равноправными узлами в одной виртуальной 
локальной подсети. Больше не нужно было настраивать постоянные 
односторонние пробросы.</li><li>Дополнительный бонус:
 Поскольку удаленный VPS был куплен в Нидерландах, через этот же VPN я 
автоматически получил безопасный доступ ко всем зарубежным ресурсам.</li></ul><p>Для реализации схемы на удаленном VPS был развернут контейнер wg-easy с поддержкой AmneziaWG, а на домашнем мини-ПК — клиентский контейнер Amnezia (сборка из Dockerfile с использованием amnezia-tools  и модулем ядра хоста).</p><p>И
 именно здесь я поймал самый изнурительный баг проекта. После 
развертывания трафик упорно шёл только в одну сторону. Часов 8 ушло на 
диагностику iptables, маршрутов и чтение зарубежных форумов (что 
бесполезно, учитывая специфику наших блокировок). Оказалось, провайдер 
просто дропал обратный трафик стандартного WireGuard, так как пакеты шли
 без маскировки. Причина крылась в docker-compose.yml: у меня было прописано image: ghcr.io/wg-easy/wg-easy:latest. Как выяснилось, тег latest  на Docker Hub намертво прилип к старой 14-й версии, а поддержка параметров AmneziaWG появилась только в ветке 15.x. Изменение тега на конкретную версию (15.3) решило проблему за секунду.</p><p>Благодаря
 переходу конфигурация получилась максимально простой, основные отличия 
от стандартной документации выделил в коде: (в основном то, на что 
пришлось долго рыть информацию)</p><h3>Настройка Nginx</h3><p>Чтобы
 сервисы были доступны исключительно внутри подсети VPN, я задействовал 
Nginx. Доступ к приложениям был жестко ограничен на уровне конфигурации —
 веб-сервер принимает запросы только из диапазона IP-адресов 10.8.0.0/24. Любые попытки постучаться на сервер из внешнего интернета без активного VPN-туннеля автоматически сбрасываются Nginx.</p><p>Логика
 распределения завязана на proxy-протоколе: Nginx на удаленном VPS 
выступает основным входным узлом, принимает зашифрованный трафик, 
заворачивает его в заголовки с реальным IP-адресом клиента и через 
туннель перекидывает на локальный Nginx домашнего сервера. Локальный 
веб-сервер уже сам расшифровывает SSL и распределяет трафик по конечным 
Docker-контейнерам, сохраняя реальные IP в логах безопасности.</p><p>Вставлю
 один кусок кода из nginx на удаленной машине для примера, так все 
остальное примерно похоже (конфиги использовались в виде .template):</p><h3>SSL-сертификаты</h3><p>Для получения валидных SSL-сертификатов я настроил работу через автоматический Certbot по challenge-валидации DNS-01 c API Webnames. Сам домен привязан к внутреннему IP-адресу 10.8.0.1.
 Проверка через DNS позволила выпустить единый wildcard-сертификат на 
весь домен и его поддомены без необходимости держать открытым 80-й порт 
веб-сервера наружу.</p><p>Уточню, что certbot запускается автоматически 
во время выполнения Ansible плейбука, поэтому самому кроме указания 
переменных ничего делать не нужно.</p><p>В
 итоге получилась схема, при которой все сервисы доступны по красивым 
доменным именам с HTTPS, но абсолютно невидимы для внешнего интернета.</p><p>Вот настройка certbot:</p><h2>История софта</h2><p>Параллельно
 с сетевой структурой развивался и сам набор приложений. Изначально я 
хотел собрать в одном месте утилиты, которыми пользуюсь каждый день, но в
 процессе селфхостинга быстро понимаешь: нельзя просто накидать 
контейнеров и надеяться, что мини-ПК справится, а конфигурационные файлы
 не превратятся в кашу.</p><h3>Первый стек и оптимизация</h3><p>Первыми на домашнем сервере прижились медиа-сервисы: Navidrome для стриминга музыки и Audiobookshelf
 для аудиокниг и подкастов. Они легковесные, имеют отличные мобильные 
клиенты с синхронизацией прогресса и полностью закрывают мои 
потребности. Позже к ним добавился Nextcloud как единое независимое облако для файлов, контактов и семейных документов.</p><p>Затем встал вопрос безопасного хранения паролей. Сначала я смотрел в сторону оригинального Bitwarden, но в итоге я выбрал Vaultwarden
 — альтернативный сервер на Rust, полностью совместимый с API Bitwarden.
 Он потребляет считанные мегабайты оперативной памяти и работает 
идеально. Дополнительно для удобства управления всей этой распределенной
 Docker-инфраструктурой в локальный стек был добавлен Portainer. (+ Portainer Agent на удаленный сервер)</p><p>Из интересных моментов, где мне пришлось немного больше возиться, чем с остальными сервисами это nextcloud настройка:</p><h3>Ошибки проектирования: почему я удалил Matrix (Synapse)</h3><p>Не все решения прошли проверку временем. На этапе использования Tuna и FRP я развернул сервер Matrix (Synapse)
 для защищенного обмена сообщениями. Мне казалось это крутой идеей, но 
когда я окончательно перешел на AmneziaWG, целесообразность мессенджера 
внутри закрытого туннеля сошла на нет.</p><p>Synapse требовал слишком 
много ресурсов, впустую расходовал оперативку домашнего ПК и усложнял 
конфиг Nginx. При этом реальной пользы для семьи он не приносил. Для 
критических алертов инфраструктуры и повседневного общения проще и 
эффективнее оказалось использовать Telegram. (плюс алертинг настроен 
именно через него) В итоге я полностью выпилил Synapse из стека, 
освободив ресурсы.</p><p>Вместо него я добавил в связку к wg-easy локальный AdGuard Home.
 Теперь он работает прямо внутри VPN-сети: очищает весь трафик от 
рекламы и трекеров на лету, кэширует DNS-запросы и не дает истории 
веб-серфинга улетать внешним провайдерам.</p><p>Основной проблемой с 
которой я столкнулся при использовании AdGuard Home, так это то что я 
так и не понял как заставить использовать AmneziaVPN клиент AdGuard как 
основной DNS, при этом AmneziaWG работает прекрасно. Как я понимаю дело в
 том что AmneziaWG работает намного проще на уровне ip и у него нету 
никаких доп фильтров, настроек и подобного, поэтому он просто берет 
данные из конфига.</p><h3>От костылей на Bash к декларативному Ansible</h3><p>Весь
 стек на обоих серверах разворачивался через bash скрипты, что было уж 
очень плохо с точки зрения идемпотентности. Во первых из-за bash мне 
постоянно приходилось очищать сервера, так как нормальных проверок у 
меня не было и писать я их не хотел, а также было много костылей с 
импортом переменных, записями в файлы и подобным.</p><p>Так я пришел к декларативному подходу и Ansible.
 Теперь вся конфигурация описывается в виде плейбуков и ролей, 
отражающих конечное желаемое состояние серверов. Конфиденциальные данные
 перенесены в файл secrets.yml, а хрупкие конструкции 
автоматизированы через шаблоны Jinja2. Проект стал идемпотентным: если 
шаги уже выполнены, Ansible их просто пропускает.</p><p>В итоге 
получилось несколько yaml файлов для стандартной настройки системы 
(bootstrap_os.yml) и для настройки каждого из хостов (setup_local.yml и 
setup_remote.yml). В итоге теперь все что нужно чтобы полностью с нуля 
развернуть проект - скачать Ansible, несколько других зависимостей на 
свой рабочий пк и запустить один manage_deploy.sh, в котором можно будет
 выбрать сценарий как будет вести себя Ansible и спокойно дождаться 
разворачивания сервисов.</p><p>Также благодаря Ansible я удобно 
реализовал переносимость проекта. Так как я решил не использовать тома 
docker, и вместо этого храню все в папках, чтобы перенести старые данные
 проекта нужно просто скопировать папку apps-data и положить ее в нужное
 место и все само заработает после повторного развертывания проекта. В 
Ansible выделяется отдельная пауза для этого.</p><p>Вот пример основного плейбука deploy.yml:</p><h3>Тестирование мультидистрибутивности с помощью Vagrant</h3><p>Проект
 изначально затачивался под работу на трех дистрибутивах: Ubuntu, Debian
 и Arch Linux. Тестировать Ansible-плейбуки прямо на рабочей локальной 
машине (в моем случае — EndeavourOS) слишком рискованно, а создавать 
виртуальные машины руками — долго и неудобно.</p><p>Решением стал Vagrant,
 позволяющий за пару минут развернуть чистые ОС в VirtualBox из готовых 
образов. Но в процессе настройки мультивендорного стенда в режиме 
сетевого моста (public_network) всплыли две критические проблемы:</p><ol><li>Конфликт DNS:
 По умолчанию Vagrant создает NAT-интерфейс для управления нодой. При 
включении второго (публичного) интерфейса для локальной сети ломался 
дефолтный DNS-резолвер. Проблему пришлось решать принудительной очисткой
 и перезаписью файла /etc/resolv.conf через inline-скрипт автоматизации Vagrant.</li><li>Проблема с GRUB на Debian: В используемом базовом образе generic/debian12
 конфигурация GRUB сохраняла жесткую привязку к конкретному имени диска 
из окружения сборщика. При повторном развертывании плейбуков на тестовом
 стенде это приводило к сбоям загрузчика. Чтобы автоматизировать 
очистку, пришлось внедрить скрипт, который на лету определяет имя 
системного диска через lsblk и автоматически передает правильные параметры в загрузчик через утилиту debconf-set-selections.</li></ol><p>Вот код Vagrantfile: (в node.vm.provision происходит основное решение ошибок)</p><p>Надежная система бэкапов на базе BorgmaticДля создания резервных копий я внедрил Borgmatic
 (удобную надстройку над дедуплицирующим инструментом Borg Backup). Весь
 процесс автоматизирован с помощью связки системных юнитов borgmatic.service и borgmatic.timer. В бэкап уходят две ключевые директории: apps-data (конфигурации приложений и баз данных) и PersonalData (медиатека: музыка, книги, подкасты, файлы Nextcloud).</p><p>Развертывание
 системы бэкапов полностью берет на себя Ansible. Мне достаточно указать
 UUID внешнего жесткого диска — скрипт сам проверит его наличие в 
системе, примонтирует в нужную директорию, создаст зашифрованный 
репозиторий и настроит политику ротации (хранение 7 ежедневных, 4 
еженедельных и 6 ежемесячных копий). Также в Prometheus выведен 
мониторинг самого репозитория .borg для отслеживания его размера и статуса успешности архивации.</p><p>Главная
 проблема при бэкапе работающих Docker-контейнеров — риск скопировать 
базу данных в «битом» или неконсистентном состоянии, если в момент 
создания архива в нее шла активная запись. Чтобы решить эту проблему, я 
задействовал механизм хуков в конфигурации Borgmatic.</p><p>Перед началом резервного копирования автоматически срабатывает команда остановки контейнеров проекта (docker-compose down),
 а после успешного завершения (или в случае возникновения непредвиденной
 ошибки) контейнеры автоматически поднимаются обратно в фоновом режиме. 
Для удобного просмотра архивов и быстрого восстановления файлов я 
развернул веб-интерфейс Borg UI.</p><p>Конфигурация borgmatic: (использую как Jinja2 шаблон, чтобы Ansible в плейбуках сам подставил переменные)</p><h2>Наблюдаемость (Observability) уровня Enterprise</h2><p>В последних релизах (v1.2.0 и v1.3.0) фокус проекта сместился на мониторинг и работу с логами.</p><h3>Эволюция алертинга и переход на Gatus</h3><p>Изначально для мониторинга доступности я смотрел на Uptime Kuma, но отказался из-за отсутствия удобной декларативной настройки через конфиги. Затем я развернул связку Blackbox Exporter и Alertmanager
 с уведомлениями в Matrix. Но тут крылась логическая несостыковка: весь 
алертинг был завязан на локальном ПК, и в случае его аппаратного отказа я
 бы просто лишился уведомлений.</p><p>Тогда я решил вернуть Uptime Kuma,
 но развернуть его на удаленном VPS в качестве внешнего «сторожа» и 
автоматизировать его настройку через Python-скрипт с библиотекой uptime-kuma-api. Но и тут ждали «грабли» — библиотека не обновлялась три года и намертво ломалась на свежих версиях Kuma.</p><p>В итоге идеальным решением стал Gatus.
 Он изначально проектировался под управление через YAML-конфиги и 
поддерживает отправку алертов, если сервер не отвечает. Из-за специфики 
фронтенда Gatus (он не умеет работать из подкаталога типа /gatus), мне пришлось перенести его и wg-easy на полноценные субдомены gatus. и wireguard.</p><p>Для Gatus получился простой конфиг:</p><p>Для мониторинга аппаратных ресурсов удаленного и локального серверов была развернута связка node-exporter + cAdvisor. Все уведомления теперь приходят мгновенно в Telegram-бота. Чтобы 
избежать лавины одинаковых сообщений (например, при перезагрузке хоста),
 в Alertmanager настроена жесткая группировка и дедупликация событий. 
Также добавлен экспортер для AdGuard Home, выводящий статистику 
заблокированных запросов в Grafana.</p><h3>Централизованные логи: Loki + Grafana Alloy</h3><p>В релизе v1.3.0 в стек была добавлена централизованная система сбора логов Loki. Вместо устаревшего Promtail в качестве агента сбора я применил Grafana Alloy.</p><p>Он
 эффективно собирает логи со всех запущенных Docker-контейнеров, парсит 
их и передает в Loki. Теперь вся история событий, ошибок веб-сервера 
Nginx или падений внутренних приложений доступна в едином интерфейсе 
Grafana с возможностью удобной фильтрации через LogQL, что значительно 
упрощает отладку.</p><p>Конфиг Loki:</p><p>Конфиг Grafana Alloy: (локальный конфиг)</p><h2>Интерфейс: переход на Homepage</h2><p>Изначально для 
домашней страницы я написал кастомную минималистичную HTML-панель с 
Glassmorphism-дизайном. Выглядело это красиво, но добавлять новые 
сервисы вручную через постоянную правку исходного кода было крайне 
неудобно.</p><figure><img src="https://media.tproger.ru/user-uploads/139471/2026-07-15/8a8f2752-8aac-4aa5-898e-98affd01cdff.webp" alt="" /><figcaption>HTML + CSS</figcaption></figure><p>В итоге я заменил самописную страницу на полноценный комьюнити-проект Homepage.
 Это дало некоторую гибкость: вся панель настраивается через простые 
YAML-файлы и поддерживает встроенные виджеты интеграции. Пока что она 
простенькая, но возможно в будущем сделаю что-то более продвинутое.</p><figure><img src="https://media.tproger.ru/user-uploads/139471/2026-07-15/90c65d4a-1310-4a30-b1ad-9e4d3083959d.webp" alt="" /><figcaption>Homepage</figcaption></figure><h2>Заключение</h2><p>Постарался
 подробно рассказать о структуре проекта и как я к этому пришел, очень 
много я не добавил, если пост зайдет, то я обязательно более подробно 
пройдусь по некоторым моментам: как я настраивал Matrix и на каком 
моменте я решил его убрать, как собирал локальный amnezia 
контейнер-клиент, что нового я добавил в релизе 1.4.0 и другое.</p><p>Также
 я перешел с manage_deploy.sh на отдельный GUI клиент, который 
будет полностью автоматизировать процесс подготовки к deploy. (написан на Go Wails). Про это тоже возможно сделаю статью.</p><p>Вся кодовая база проекта, подробная документация, инструкции по развертыванию открыты и доступны для сообщества:</p><p>🔗 GitHub-репозиторий: <a href="https://github.com/canntstand/ServeHub-2" rel="noopener noreferrer nofollow">https://github.com/canntstand/ServeHub-2</a></p><p>Это
 моя первая статья на этом сайте и в то же время первый личный проект, которому я 
отдал так много времени (3 месяца). Буду рад вашему фидбеку в 
комментариях!</p>]]></content:encoded>
    </item>
    <item>
      <title>Один фреймворк для Android и iOS: звучит круто, работает?  Нет</title>
      <link>https://tproger.ru/articles/odin-frejmvork-dlya-android-i-ios-zvuchit-kruto-rabotaet-net</link>
      <comments>https://tproger.ru/articles/odin-frejmvork-dlya-android-i-ios-zvuchit-kruto-rabotaet-net?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Роман Новохацкий]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/odin-frejmvork-dlya-android-i-ios-zvuchit-kruto-rabotaet-net</guid>
      <description><![CDATA[<p>Почему единый кроссплатформенный фреймворк для автотестов Android и iOS не работает на практике и когда стоит разделить его на два отдельных проекта.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/odin-frejmvork-dlya-android-i-ios-zvuchit-kruto-rabotaet-net">Один фреймворк для Android и iOS: звучит круто, работает?  Нет</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Распознавание]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Swift]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[Kotlin]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 23 Jul 2026 13:20:45 GMT</pubDate>
      <content:encoded><![CDATA[<p>Я сделал автотесты на Appium для Android и iOS в одном проекте. Один репозиторий, общий фреймворк, общие Page Objects, общие steps. Красота.</p><p>Потом проект вырос, в команду пришли ещё люди, и стало понятно: этот красивый монолит пора разделять.</p><p>Это было взвешенное решение. В какой-то момент общий фреймворк превратился в поле мерж-конфликтов, где ты уже не тесты пишешь, а разбираешься, кто чей page object сломал и почему Android отвалился после правки для iOS.</p><p>Appium тут ни при чём, как и скорость тестов. Проблема была в архитектуре: один общий слой для двух разных платформ начал мешать сильнее, чем помогать.</p><p>Как говорил один мой коллега, перефразируя классическое “вам шашечки или ехать”:</p><blockquote>Ты сюда страдать пришёл или тесты писать?</blockquote><p>После этого решение разделить Android и iOS на два проекта стало очевидным.</p><p>Сейчас у меня два отдельных проекта: mb-android-tests и mb-ios-tests. И знаете что? Это лучшее архитектурное решение за всё время на этом проекте. Серьёзно.</p><p><b>Контекст: что за проект и почему это важно</b></p><p>Финтех. Нативное приложение. Отдельные кодовые базы, Kotlin на Android, Swift на iOS. И UI там не «три кнопки и список», формы с десятками полей, кастомные контролы, WebView-вставки, платежи, валютные операции, бюджетные переводы. Ну вы поняли.</p><p>Стек: Java 21, TestNG, Appium 2.x, Selenide, Allure, Maven. CI на GitLab, крутится на Mac Mini. 5 Android-эмуляторов, 4 iOS-симулятора, 9 Appium-серверов — по одному на устройство.</p><p>Но это сейчас. А начиналось всё с одного жирного монолита.</p><p><b>Старый проект: 8 модулей и конструктор-монстр</b></p><figure><img src="https://media.tproger.ru/user-uploads/139426/2026-07-07/54be52bb-7e50-4e11-b624-86cc1ce0766b.webp" alt="" /></figure><p>Идея была «как в книжке»: один репозиторий, модульная структура, переиспользование. DRY во все поля. Ну а чё, красиво же.</p><p>8 модулей. Один mvn clean install. Все зависят от mobile-automation-framework, в котором живут DriverFactory, BaseTest, общие Page Objects и слой Steps.</p><p>А DriverFactory принимал <b>11 параметров</b>. Одиннадцать, Карл.</p><p>Половина нужна только Android, другая только iOS. Но метод один. Потому что так более по программистцки, как написано в каждой второй статье про архитектуру автотестов.</p><p>Когда я работал один, было норм. Ты сам знаешь, от куда что идет.</p><p>А потом пришли люди.</p><p><b>Почему с людьми всё навернулось</b></p><p><b>Мерж-конфликты каждый божий день</b></p><p>Вот конкретная ситуация. Один человек правит LoginPage в общем фреймворке, добавляет метод для iOS, меняет локатор. Второй в тот же момент рефакторит этот же LoginPage под новую версию Android-приложения.</p><p>Мерж. Конфликт.</p><p>И тут начинается самое весёлое: какой локатор правильный? Для Android? Для iOS? Для обоих? Кто будет разбираться? Тот, кто мёрджит? А он вообще контекст понимает?</p><p>Это не единичный случай. Это было <b>каждый</b> день. Потому что mobile-automation-framework получился общим модулем, от которого зависят все. И все туда лезут. Постоянно.</p><figure><img src="https://media.tproger.ru/user-uploads/139426/2026-07-07/3866002d-86c5-4894-a441-2522f48dcab1.webp" alt="" /></figure><p><b>Обновление одной библиотеки = блокировка всех</b></p><p>Решил обновить java-client с 7.x на 8.x. Нормальное желание — API поменялся, MobileElement удалили, capabilities переехали на типизированные Options.</p><p>Вот что произошло в реальности:</p><ol><li>Меняю версию в parent pom.xml</li><li>MobileElement удалён → compilation error в DriverFactory, во всех DriverManager’ах</li><li>DesiredCapabilities → UiAutomator2Options / XCUITestOptions → переписываю все менеджеры</li><li>selenide-appium 1.x несовместим с java-client 8.x → обновляю до 2.x</li><li>selenide-appium 2.x требует Selenide 6.x → обновляю Selenide</li><li>Selenide 6.x ломает API page objects → переписываю page objects во всех модулях</li><li>А Selenide 6.x ещё и Java 8 не поддерживает → обновляю Java</li></ol><p>Одна библиотека.</p><p>Задача «обновить одну библиотеку» превратилась в 50+ файлов, 4-5 каскадных обновлений, 2-3 недели работы. И всё это время develop нестабилен. Все заблокированы. Тесты не запускаются.</p><p>Две недели.</p><p>Из-за одной строчки в pom.xml.</p><p><b>Page Objects с if/else — это два page object в одном файле</b></p><p>Общие Page Objects звучат красиво на бумаге: пишем один раз, используем для обеих платформ. А на практике…</p><p>Это не page object. Это два page objects, запиханных в один файл через if/else. И так в каждом методе.</p><p>А сверху ещё слой Steps. Обёртки над page objects «для читаемости». И в steps тоже if (platform), потому что логика взаимодействия разная. На Android ты скроллишь через UiScrollable семантически, «прокрути до элемента с текстом X». На iOS координатами, «двигай палец из точки A в точку B». Один метод в steps, а внутри два разных мира.</p><p>В какой-то момент ловишь себя на мысли: я же не тесты пишу. Я подгоняю pages и steps под две платформы, чтобы фреймворк не развалился. Это уже не автоматизация тестирования, это поддержка фреймворка ради поддержки фреймворка.</p><p><b>Каждый работает в своём темпе и все друг другу мешают</b></p><p>У одного задача покрыть тестами новый экран на Android. У второго пофиксить падающие тесты на iOS. У третьего добавить тестовые данные.</p><p>Все трое лезут в mobile-automation-framework. Все трое меняют pom.xml, BaseTest, page objects. Каждый в своей ветке.</p><p>А потом мёрдж.</p><p><b>Технические причины, которые добили окончательно</b></p><p>Ладно, человеческий фактор. Но были и чисто технические штуки, которые окончательно убедили меня, что кроссплатформа тут бессмысленна.</p><p><b>Локаторы: работай с тем, что дают</b></p><p>Сразу скажу то, о чём мало кто пишет в статьях: в мобильной автоматизации ты работаешь с тем, что дают, а не с тем, что хотелось бы.</p><p>В теории есть AccessibilityID единый локатор для обеих платформ. Звучит хорошо. А на практике? Попробуй попросить мобильных разработчиков расставить одинаковые accessibility-идентификаторы на сотнях экранов. На Kotlin и Swift. Одновременно. Они тебя вежливо пошлют, но скорее всего не вежливо. И будут правы, у них свои спринты, свои дедлайны, и твои автотесты в их приоритетах где-то между «поправить тень у кнопки» и «никогда».</p><p>Так что реальный выбор:</p><p><b>XPath -</b> работает, но на iOS может быть тормозным. На Android через UiSelector быстро, нативно, надёжно. На iOS через NSPredicate тоже ок. А «универсальные» XPath типа //*[@text='Войти' or @label='Войти']  это путь к боли, потому что Page Source на двух платформах два совершенно разных XML-дерева.</p><p><b>Координаты -</b> костыль? Да. Но иногда единственный вариант. Когда у тебя кастомный контрол без accessibility-свойств, а разработчик говорит «это декоративный элемент», ты либо тыкаешь по координатам, либо не тестируешь.</p><p><b>OpenCV</b> - есть ещё вариант с распознаванием элементов по картинке. Для некоторых кейсов реально выручает. Но это отдельная тема на целую статью, может напишу потом.</p><p>Суть в том, что «напиши один локатор и работай на двух платформах» это миф. Page Source на Android это android.widget.Button с resource-id. На iOS  XCUIElementTypeButton с name и label. Разные типы элементов, разные атрибуты, разная глубина вложенности. Разные миры.</p><p><b>StaleElementReferenceException — «подарок» от iOS</b></p><p>Android рендерит UI через Choreographer синхронно с VSYNC. Элемент появился → стабилен → кликаем.</p><p>iOS рендерит через CoreAnimation с неявными анимациями. Элемент есть в дереве, но ещё анимируется. Формально кликабелен, фактически хрен.</p><p>Стандартный WebDriverWait с elementToBeClickable это не ловит. Элемент «кликабелен» по мнению Appium wait завершается. А потом click() падает, потому что DOM изменился между вызовами.</p><p>На Android этой проблемы нет вообще. Тот же тест, тот же wait, тот же код зелёный на Android, красный на iOS. Один и тот же метод, два разных результата. И это не баг это фундаментальное различие платформ.</p><p>Кастомные wait-стратегии для iOS отличаются от Android принципиально. Пихать их в один фреймворк строить leaky abstraction, которая протекает на каждом шаге.</p><p><b>Жесты — два разных мира</b></p><p>Свайп вниз на Android:</p><p>Свайп вниз на iOS:</p><p>Чувствуете разницу? И даже длительность свайпа важна: на Android 200мс это нормальный скролл. На iOS 200мс это fling, и элемент улетает за экран.</p><p>«Кроссплатформенная» обёртка для скролла функция на 40 строк с двумя ветками if (platform), внутри каждой и ещё if для performSwipeDown() vs performSwipeUp(). На 50+ экранах таких обёрток, которых десятки.</p><p>И каждая место для бага.</p><p><b>Решение: разделяй и властвуй</b></p><p>Решение было болезненным. Я реально откладывал, потому что казалось, что это шаг назад. Дублирование кода, нарушение DRY, всё такое. Мозг сопротивлялся.</p><p>А потом я просто сел и разделил.</p><p>Никаких общих page objects. Никаких общих steps. Никакого общего DriverFactory с 11 параметрами. Каждый проект со своим pom.xml, свои зависимости, свой BaseTest, свои локаторы.</p><p>Что осталось общего: подход к структуре (Maven + TestNG + Allure), CI-шаблоны, принципы организации. Но не код. Код полностью раздельный.</p><p><b>Что поменялось на практике</b></p><p>В Android-проекте DriverManager типизирован под AndroidDriver. В iOS под IOSDriver. Не AppiumDriver&lt;MobileElement&gt; с кастами и проверками, а конкретный тип для конкретной платформы. IDE подсказывает только релевантные методы. Компилятор ловит ошибки на этапе сборки, а не в рантайме.</p><p>BaseTest принимает ровно те параметры, которые нужны. Android: deviceName, platformVersion, udid, appPackage, appActivity, systemPort, serverUrl, appPath — 8 штук, все релевантные. iOS: deviceName, platformVersion, udid, appPath, serverUrl, wdaLocalPort — 6. Никаких @Optional("systemPort") со строкой “systemPort” в качестве дефолта.</p><p><b>А мерж-конфликты?</b></p><p>Когда один человек работает в mb-android-tests, а второй в mb-ios-tests то они <b>вообще</b> не пересекаются. Разные репозитории. Конфликт невозможен физически.</p><p>Обновление java-client в Android-проекте не затрагивает iOS. Хочешь обновить, обновляй. iOS продолжает работать на старой версии.</p><p>Добавить новый параметр для iOS? Меняешь BaseTest и testng.xml в iOS-проекте. Android даже не узнает.</p><p>Это прям кайф.</p><p><b>А как же дублирование кода?!</b></p><p>Конечно, конечно. Первый вопрос, который задают: «Но ведь ты пишешь тесты дважды!»</p><p>Нет.</p><p>Я пишу каждый тест один раз и без костылей. Без if (platform) в каждом методе. Да, для одного и того же экрана есть два теста, один для Android, один для iOS. Но каждый из них чистый, понятный, заточенный под свою платформу.</p><p>В старом варианте я тоже «писал один раз», а потом тратил столько же времени на поддержку if/else, мерж-конфликты и каскадные обновления. «Экономия» на создании оборачивалась переплатой на поддержке. С процентами.</p><p><b>Когда кроссплатформа всё-таки ок</b></p><p>Я не топлю за то, что кроссплатформенный фреймворк абсолютное зло. Есть ситуации, где он работает:</p><p>Приложение простое, пара экранов, стандартные контролы, минимум кастомного UI.</p><p>UI реально идентичен на обеих платформах. Бывает, наверное.</p><p>Команда из одиного человека. Сам пишешь, сам мёрджишь, сам разруливаешь. Голова справляется.</p><p>Минимум жестов. Нет сложных свайпов, drag-and-drop, pinch-to-zoom.</p><p>Если у тебя финтех, банк, enterprise-приложение с сотнями экранов, кастомными контролами и тремя+ QA, то два проекта дешевле. Не в строках кода, а во времени. В нервах. В часах, потраченных на мерж-конфликты вместо написания тестов.</p><p><b>Итого</b></p><p>Два проекта это не шаг назад и не двойная работа. Со стороны может выглядеть именно так, но на практике ты пишешь каждый тест один раз, под конкретную платформу, без лишних компромиссов. Потом поддерживаешь его без постоянных мерж конфликтов, каскадных обновлений и if/else в каждом втором методе.</p><p>Кроссплатформенный фреймворк на Appium для сложного нативного приложения часто оказывается иллюзией экономии.</p><p>В следующей статье покажу, как у нас устроена инфраструктура для 9 параллельных устройств на одном Mac Mini: порты, bash скрипты, Appium серверы и workaround’ы, которых нет в документации. Спойлер: там тоже всё не совсем как в гайдах.</p>]]></content:encoded>
    </item>
    <item>
      <title>Git умеет игнорировать файлы не только через .gitignore: три уровня защиты от мусора в репозитории</title>
      <link>https://tproger.ru/articles/git-umeet-ignorirovat-fajly-ne-tolko-cherez-gitignore-tri-uro</link>
      <comments>https://tproger.ru/articles/git-umeet-ignorirovat-fajly-ne-tolko-cherez-gitignore-tri-uro?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/git-umeet-ignorirovat-fajly-ne-tolko-cherez-gitignore-tri-uro</guid>
      <description><![CDATA[<p>Разбираем, как Git игнорирует файлы на уровне репозитория, машины и локальной копии. Узнайте, когда использовать .gitignore, .git/info/exclude и глобальный ignore.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/git-umeet-ignorirovat-fajly-ne-tolko-cherez-gitignore-tri-uro">Git умеет игнорировать файлы не только через .gitignore: три уровня защиты от мусора в репозитории</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Инструменты командной строки]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 09 Jul 2026 05:38:39 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы работаете с Git, .gitignore для вас — привычная табличка у входа в репозиторий: сюда нельзя, туда нельзя, node_modules и .env оставьте за дверью. Но Git умеет фильтровать нежелательные файлы на трёх уровнях — и только один из них версионируется вместе с кодом. Остальные два спасают, когда правила общие не подходят: личные заметки, локальные скрипты, артефакты операционной системы.</p><p>Игнорирование в Git — это не магия, а просто набор шаблонов. Когда вы запускаете git status, Git сверяет имена файлов с тремя списками и решает, показывать их или нет. Важно: игнорируемый файл всё ещё лежит в рабочей директории, просто Git не предлагает его добавить в индекс.</p><ul><li>.gitignore — правила для всего репозитория, версионируются и делятся с командой.</li><li>.git/info/exclude — локальные правила одного клона, не попадают в коммиты.</li><li>~/.config/git/ignore — глобальные правила для всех репозиториев на машине.</li><li>git check-ignore -v filename покажет, какой именно файл игнорирует файл.</li><li>Правильный выбор уровня избавляет команду от конфликтов и лишних правок .gitignore.</li></ul><h2>Три файла, которые говорят Git «не замечай»</h2><p>Каждый из трёх файлов отвечает за свой масштаб. Отличаются они не синтаксисом — он везде одинаковый, — а областью действия и тем, попадают ли изменения в историю репозитория.</p><h3>.gitignore — общие правила репозитория</h3><p>Это классика. Файл лежит в корне проекта или в подкаталогах, попадает под контроль версий и работает одинаково у всех, кто клонирует репозиторий. Сюда стоит писать всё, что относится к проекту целиком: зависимости, сборочные артефакты, локальные конфиги IDE, тестовые базы.</p><p>Плюс очевиден: все члены команды видят одни и те же правила. Минус тоже очевиден: если правило нужно только вам, каждый раз править общий .gitignore и создавать коммит — избыточно.</p><h3>.git/info/exclude — личные правила для одного репозитория</h3><p>Внутри каталога .git каждого клона есть файл info/exclude. Он устроен так же, как .gitignore, но не входит в коммиты. Это идеальное место для файлов, которые есть только у вас: черновики, личные заметки, экспериментальные скрипты, локальные дампы.</p><p>Сценарий простой: вы держите в репозитории файл notes.txt с личными пометками. Добавлять его в .gitignore не хочется — коллегам он не нужен, а в .git/info/exclude он исчезает из git status только на вашей машине.</p><h3>~/.config/git/ignore — глобальные правила для всей машины</h3><p>Третий уровень действует на все репозитории текущего пользователя. Если у вас macOS, вы наверняка устали видеть .DS_Store в выводе git status. Вместо того чтобы добавлять его в каждый .gitignore, проще вынести на глобальный уровень.</p><p>Путь к глобальному файлу можно переопределить. Например, чтобы использовать .gitignore_global в домашней директории, выполните:</p><p>Вернуть значение по умолчанию можно командой git config --global --unset core.excludesFile.</p><h2>Как проверить, кто именно игнорирует файл</h2><p>Когда правил много, легко забыть, какой файл за что отвечает. Git предоставляет команду git check-ignore -v, которая показывает источник игнорирования: название файла с правилами, номер строки и сам шаблон.</p><p>Если файл игнорируется .gitignore, вывод будет начинаться с .gitignore; если локальным exclude — путь к нему; если глобальным ignore — путь в домашней директории. Если команда ничего не выводит, значит файл никто не игнорирует.</p><p><b>Полезно:</b><br />git check-ignore работает и с каталогами. Передайте путь к папке, чтобы узнать, почему она не попадает в индекс.</p><h2>Когда какой уровень использовать</h2><ul><li>.gitignore — правила, общие для всей команды: зависимости, сборочные артефакты, секреты.</li><li>.git/info/exclude — персональные файлы внутри одного репозитория, которые не должны светиться в коммитах.</li><li>~/.config/git/ignore — файлы ОС и редактора, которые мешают в любом проекте на вашей машине.</li></ul><p>Главный принцип: чем шире правило, тем реже его стоит менять. Глобальный ignore настраивается один раз при настройке рабочей машины, а .gitignore живёт вместе с проектом и развивается вместе с ним.</p><h2>Выводы</h2><p>Git предлагает не один, а три уровня игнорирования, и каждый решает свою задачу. .gitignore отвечает за командные договорённости, .git/info/exclude — за личный порядок в одном репозитории, а ~/.config/git/ignore — за чистоту рабочей машины в целом. Разделение уровней помогает не засорять общие правила личными исключениями и не тащить в коммиты то, что нужно только вам.</p><blockquote>Хороший .gitignore защищает команду, а правильное использование exclude и global ignore защищает ваше собственное ментальное здоровье при работе с кодом.</blockquote><p>Источник: <a href="https://nelson.cloud/.gitignore-isnt-the-only-way-to-ignore-files-in-git/" rel="noopener noreferrer">Nelson Ameyin, «.gitignore isn’t the only way to ignore files in Git»</a>.</p><p>Попробуйте проверить свои репозитории: запустите git check-ignore -v на паре подозрительных файлов — возможно, вы найдёте правила, про которые давно забыли.</p>]]></content:encoded>
    </item>
    <item>
      <title>Godot запретил код от ИИ-агентов: почему open source борется с AI slop</title>
      <link>https://tproger.ru/articles/godot-zapretil-kod-ot-ii-agentov-pochemu-open-source-boretsya-s-a</link>
      <comments>https://tproger.ru/articles/godot-zapretil-kod-ot-ii-agentov-pochemu-open-source-boretsya-s-a?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/godot-zapretil-kod-ot-ii-agentov-pochemu-open-source-boretsya-s-a</guid>
      <description><![CDATA[<p>Godot Foundation запретила ИИ-агентам и vibe coding участвовать в разработке. Разбираем, почему open source защищает mentorship pipeline и какие проекты пошли дальше.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/godot-zapretil-kod-ot-ii-agentov-pochemu-open-source-boretsya-s-a">Godot запретил код от ИИ-агентов: почему open source борется с AI slop</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Jul 2026 12:52:18 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы в последние месяцы открывали пул-реквест в крупный open-source-проект, скорее всего, заметили: количество «сомнительно идеальных» патчей резко выросло. 30 июня 2026 года <b>Godot Foundation</b> официально обновила политику contributions и практически полностью запретила ИИ-агентам и «vibe coding» участвовать в разработке движка. Причина не только в качестве кода, но и в том, что ревью перестаёт воспитывать новых мейнтейнеров, если на другой стороне — не человек, а модель.</p><p><a href="https://godotengine.org/">Godot Engine</a> — это открытый кроссплатформенный игровой движок, который многие инди-разработчики рассматривают как альтернативу Unity. Проектом управляет некоммерческая Godot Foundation, а код собирается из пул-реквестов со всего мира. Это делает правила contributions ключевым инструментом выживания экосистемы.</p><p>Основной тезис обновления: <b>любой существенный код должен быть написан человеком</b>, который способен отвечать за него. Автономные ИИ-агенты, «vibe-coded» PR и ИИ-сгенерированный текст в обсуждениях попадают под запрет. Мелкие вспомогательные задачи — code completion, регулярки, find-and-replace — остаются, но с обязательным раскрытиием.</p><ul><li>Godot Foundation запретила ИИ-агентам и «vibe coding» создавать пул-реквесты с существенным кодом.</li><li>Разрешены только мелкие вспомогательные операции: code completion, regex, find-and-replace с обязательным дисклеймером.</li><li>Новички (≤3 принятых PR) теперь должны получать одобрение мейнтейнеров перед новыми фичами и крупными рефакторингами.</li><li>Главный аргумент — ревью кода — это не только проверка, но и менторство будущих мейнтейнеров, а ИИ из этого контура выпадает.</li><li>Похожие ограничения уже ввели Zig, Ghostty и curl: проблема AI slop стала системной для open source.</li></ul><h2>Что именно запрещено</h2><p>В официальном посте <a href="https://godotengine.org/article/contribution-policy-2026/">Changes to our Contribution Policies</a> Foundation перечисляет три запрещённые категории. Важно, что они касаются не только ботов, но и людей, которые копируют ИИ-вывод в PR, даже если потом вручную проверяют и дисклейсят.</p><ul><li><b>Автономные ИИ-агенты и «vibe coding».</b> PR, созданные без глубокого участия человека, уже отклоняются автоматически.</li><li><b>ИИ как автор существенного кода.</b> Блоки логики, сгенерированные моделью, не принимаются независимо от того, кто нажал «Submit».</li><li><b>ИИ-сгенерированный текст в коммуникации.</b> Обсуждения с мейнтейнерами должны вестись людьми; исключение — машинный перевод человеческого текста.</li></ul><p>Одновременно Foundation добавила барьер для новых участников: до трёх принятых PR — и вы не можете предлагать новые фичи или большие рефакторинги без явного разрешения. Цель не оскорбить новичков, а заставить их сначала разобраться в кодовой базе и завоевать доверие через багфиксы и документацию.</p><h2>Почему это больше, чем «слишком много PR»</h2><p>Сама по себе нагрузка на ревьюеров — старая open-source-боль. Но здесь добавляется другой эффект: <b>обратная связь на ИИ-код не учит никого</b>. Если модель сгенерировала патч, комментарий мейнтейнера не улучшит следующий выход той же модели, а автор-человек часто не понимает кода достаточно, чтобы довести правку до ума.</p><blockquote>Reviewing PRs is already tedious work, but it is rewarding because reviewers generally feel that their efforts are contributing to educating a new contributor — who may become a future maintainer/reviewer. If your feedback on PRs is just being absorbed by a machine and not going towards mentoring a potential future maintainer, it becomes much harder to justify spending your free time on PR review.</blockquote><p>В <a href="https://www.gamedeveloper.com/business/godot-to-ban-almost-all-ai-coding-contributions">интервью Game Developer</a> Foundation прямо говорит: «AI cannot take responsibility, and we can’t trust heavy users of AI to understand their code enough to fix it». Это не ненависть к ИИ как технологии, а признание, что <b>ответственность за код должен нести конкретный человек</b>.</p><h2>«Contributor poker»: инвестиция в человека, а не в код</h2><p>Эта логика не нова. В апреле 2026 года язык программирования <a href="https://ziglang.org/">Zig</a> ввёл схожий zero-tolerance policy для ИИ-помощи в contributions. Вице-президент Zig Software Foundation Лорис Кро назвал ревью «contributor poker»: в покере вы играете против человека, а не против карт. Аналогично мейнтейнер вкладывает время не в конкретный PR, а в человека, который его прислал.</p><blockquote>In contributor poker, you bet on the contributor, not on the contents of their first PR.</blockquote><p>Когда PR написан ИИ, ставка срывается: ревью не превращает автора в будущего мейнтейнера, потому что автор не учится. Именно поэтому Godot и Zig формулируют запрет не как «ИИ плох», а как «менторская петля разрывается».</p><h2>Godot не один: Zig, Ghostty и curl</h2><p>Та же проблема AI slop в разных проявлениях встречается и в других крупных проектах. Терминал Ghostty ограничил поток ИИ-сгенерированных issue, а библиотека curl пережила настоящий DDoS фальшивыми security-репортами.</p><p><a href="https://curl.se/">curl</a> — самый известный пример. Создатель проекта Даниэль Стенберг писал, что в 2025 году доля валидных security-репортов упала примерно до одной из двадцати: «We are effectively being DDoSed». Часть отчётов содержала GDB-сессии и дампы регистров для функций, которых в curl не существует. В ответ команда <a href="https://daniel.haxx.se/blog/2025/07/14/death-by-a-thousand-slops/">закрыла bug bounty на HackerOne</a> и перешла к более жёсткой модерации.</p><p>Интересно, что curl не отвергает ИИ полностью: тот же Стенберг позже признал, что AI-сканнеры в руках экспертов находят настоящие баги. Разница между полезным инструментом и slop — в <b>проверке и ответственности человека</b>, который отправляет результат.</p><h2>Пайплайн талантов под угрозой</h2><p>Godot и Zig формулируют свой запрет в терминах mentorship pipeline — цепочки, по которой первый контрибьютор превращается в ревьюера, а ревьюер — в мейнтейнера. Если между «новичок» и «опытный разработчик» встает ИИ, обратная связь не доходит до человека, и вся цепочка останавливается.</p><p>В корпоративной среде эта же проблема звучит иначе: <a href="https://thenewstack.io/">The New Stack</a> в апреле цитировал Марка Руссиновича и Скотта Хансельмана из Microsoft, которые предупреждали: если компании будут заменять junior-разработчиков senior-инженерами с ИИ-ассистентами, «the profession’s talent pipeline collapses».</p><blockquote>We need to take steps to reduce the burden on maintainers while ensuring we still have a pipeline to mentor new contributors to become future maintainers.</blockquote><h2>Что делать разработчикам</h2><p>Запрет Godot не означает, что ИИ-инструменты нужно выбросить. Он устанавливает границу: модель может помогать в мелочах, но не может быть автором кода, за который ты не готов отвечать.</p><ol><li>Читайте <a href="https://godotengine.org/article/contribution-policy-2026/">правила contributions</a> конкретного проекта перед отправкой PR.</li><li>Раскрывайте использование ИИ для autocomplete, regex и мелких правок — честность ускоряет ревью.</li><li>Не отправляйте сгенерированные моделью блоки логики как «свой» код: вы должны понимать каждую строку.</li><li>Если у вас ≤3 принятых PR в Godot, начинайте с багфиксов и документации, а не с новых фич.</li><li>Проверяйте ИИ-репорты безопасности вручную: hallucinated уязвимости тратят время мейнтейнеров зря.</li></ol><h2>FAQ</h2><h2>Выводы</h2><p>Godot не объявляет войну искусственному интеллекту. Она объявляет войну <b>безответственному использованию</b> ИИ в том месте open source, где важнее всего доверие и обучение. Движок остаётся открытым, но правила contributions становятся жёстче — и это, скорее всего, не последний подобный шаг в индустрии.</p><blockquote>Things change every day with respect to the current suite of AI tools available. We will continue taking a conservative approach in our policies towards them, but we will re-evaluate as things evolve.</blockquote><p>Источники: <a href="https://thenewstack.io/godot-bans-ai-coding-agents/">The New Stack</a>, <a href="https://godotengine.org/article/contribution-policy-2026/">Godot Foundation</a>, <a href="https://www.gamedeveloper.com/business/godot-to-ban-almost-all-ai-coding-contributions">Game Developer</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Git в Telegram: как я избавился от JSON, победил Markdown и получил security by design</title>
      <link>https://tproger.ru/articles/git-v-telegram--kak-ya-izbavilsya-ot-json--pobedil-markdown-i-polu</link>
      <comments>https://tproger.ru/articles/git-v-telegram--kak-ya-izbavilsya-ot-json--pobedil-markdown-i-polu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Robin Gad]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/git-v-telegram--kak-ya-izbavilsya-ot-json--pobedil-markdown-i-polu</guid>
      <description><![CDATA[<p>Git в Telegram? Без JSON, с SQLite, победой над Markdown и security by design. Код, схема БД, факапы и ссылка на бота.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/git-v-telegram--kak-ya-izbavilsya-ot-json--pobedil-markdown-i-polu">Git в Telegram: как я избавился от JSON, победил Markdown и получил security by design</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Telegram]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[IBM]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Markdown]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Jul 2026 06:39:38 GMT</pubDate>
      <content:encoded><![CDATA[<p>В своём Telegram-канале я время от времени предлагаю подписчикам выбрать очередную «бредовую» идею для реализации. На этот раз победил Git в Telegram: чтобы можно было инитить проекты, пушить файлы, коммитить — и всё это прямо в мессенджере.</p><p>С практической точки зрения проект на**й не нужен. Есть GitHub, GitLab и куча нормальных инструментов. Но как эксперимент — почему бы и нет? Чисто посмотреть, можно ли заставить Telegram работать как VCS.</p><h2>Почему не JSON</h2><p>На старте я думал: «Положу всё в JSON, на кой мне база данных?» Проектов мало, пользователей немного, файлы текстовые — чего заморачиваться?</p><p>Подергал JSON туда-сюда пару дней и понял: не варик.</p><ol><li>Конкурентный доступ. Два юзера одновременно коммитят — один перезаписывает файл другого.</li><li>Целостность данных. Если бот упал в середине записи — JSON остаётся в невалидном состоянии.</li><li>Версионность. Хранить историю изменений в JSON — это просто перенести проблему из кода в структуру файла.</li></ol><p>Вывод: JSON — для конфигов, а не для данных, которые меняются каждую секунду.</p><h2>Выбор SQLite и схема БД</h2><p>Выбрал SQLite, потому что:</p><ul><li>Не надо поднимать отдельный сервер</li><li>Целостность данных на уровне движка (транзакции, foreign keys, rollback)</li><li>Всё в одном файле — скопировал и унёс</li></ul><p>Сущности:</p><ul><li>users — telegram_id, username, current_project_id</li><li>projects — owner_id, name, thread_id (каждый проект живёт в своём треде канала)</li><li>files — filename, current_version, флаг modified (файл изменился и готов к коммиту)</li><li>file_versions — мясо. Каждая версия файла с полным содержимым. Привязана к file_id и опционально к commit_id</li><li>commits — сообщение, время, ссылка на проект</li><li>commit_files — связка коммитов с версиями файлов (many-to-many, чтобы поддержать ветки)</li></ul><p>Почему так: я хотел иметь возможность откатиться к любой версии любого файла. Да, база распухнет, но текстовые файлы — это не гигабайты видео. Плюс наличие file_versions и commit_files позволяет делать diff между версиями и смотреть историю изменений.</p><p>В коде вместо голых кортежей из SQL — датаклассы:</p><h2>Маркдауновый ад</h2><p>Казалось бы: взял код, обернул в тройные апострофы, кинул в Telegram. Telegram сам подсветит синтаксис, если указать язык. Красота. В теории.</p><p>На практике Telegram использует свой диалект Markdown, где куча служебных символов: _ * [ ] ( ) ~ &gt; # + - = | { } . !</p><p>Попытка 1: заэкранировать всё подряд. Результат: код превращается в кашу. Вместо<b> </b><i>def  __init__- </i> получается <i>def |_|_init|_|_ </i> — уже не запустишь, и в канале выглядит как говно.</p><p>Попытка 2: не экранировать вообще. Telegram шлёт на**й с ошибкой «can't parse entities».</p><p>Попытка 3: экранировать только то, что реально ломает разметку. Выяснилось, что порядок важен. Сначала экранируем точки и подчеркивания, потом обратную косую черту. Но и это не панацея — последовательности типа \*</p><p>после экранирования превращаются в \\*, и Telegram снова недоволен.</p><p>Попытка 4: разбивать на части. Для больших файлов делаю превью (первые 50 строк), экранирую их, отправляю как код, а полную версию — файлом. И тут начался ад: Telegram находил ошибки в тех частях кода, которых в превью вообще не было. Оказывается, он всё равно парсил полный код, даже если отправлялась только его часть.</p><p>Попытка 5 (финал): забил на Markdown и перешёл на HTML. Telegram умеет его принимать. Да, он не такой красивый, но зато предсказуемый:</p><p>Никаких точек, подчеркиваний, обратных слешей. Просто экранируем три символа — и код летит как надо.</p><h2>Security by design</h2><p>Когда бот начал обрастать функциями, я задумался о безопасности. Чтобы никто не мог коммитить или удалять чужие файлы, начал писать проверки в каждую команду:</p><p>Добавил в /commit. Потом решил с другого аккаунта потестировать команды на чужих файлах. И тут бот на каждую команду стал выдавать «файл не найден» или «проект не найден». И я понял: безопасность уже работает. С самого начала. Из коробки. Без единой строчки кода.</p><p>Как так вышло? В таблице projects с самого начала было поле owner_id. При создании проекта я писал туда telegram_id  владельца. Все запросы к БД фильтруются по этому полю:</p><p>Показать проекты — только свои. Найти файл — только в своих проектах. Выбрать проект — только из своих. Никаких лишних проверок. Просто SQL-запросы, которые с самого начала учитывали владельца.</p><h2>Команды: от семи до двух десятков</h2><p>Изначально казалось, что команд будет немного. Но...</p><p>Жизнь рассудила иначе.</p><ul><li>База: /start, /init, /use, /list, /ls, /commit, /log, /status</li><li>Удаление: /rm, /rmproject + подтверждение</li><li>Игнор: /ignore, /ignored, /unignore</li><li>Ветки: /branch, /branches, /checkout</li><li>Диффы и просмотр: /diff, /cat</li></ul><p>Итого — уже под два десятка. И это не предел.</p><h2>Простота &gt; абстракции</h2><p>В моём коде нет абстрактных базовых классов. Совсем. Потому что они нужны только когда у тебя есть минимум две разные реализации одного и того же. В GitGram всё проще: один способ работать с БД, один способ шифровать, один способ парсить .gitignore.</p><p>Если завтра появится вторая реализация — тогда и буду делать интерфейс. А пока это просто оверхед.</p><p>В GitGram:</p><ul><li>Хочешь понять, как работает add_file — идёшь в database.py и читаешь 10 строк кода.</li><li>Хочешь увидеть обработчик /commit — открываешь bot.py и смотришь.</li></ul><p>Никаких AbstractMinerShieldEventProcessor, BaseGitGramManager, InterfaceProviderFactory.</p><p>Код должен быть тупым. Чем тупее — тем проще его читать и отлаживать.</p><h2>Что дальше</h2><p>В планах:</p><ul><li>Докрутить коллаборацию (несколько человек над одним проектом)</li><li>Приватные репозитории</li><li>Кодспейс прямо в боте (да да знаю я сошёл с ума и бла бла бла..)</li></ul><h2>Итог</h2><p>GitGram принимает файлы, режет их на куски если надо, постит в канал с подсветкой. Коммиты ходят, ветки переключаются, диффы показываются. Всё это в тредах, каждый проект отдельно.</p><p>На практике GitGram ни к чему. Но сама задумка — Git в Telegram — это же так прикольно. Просто посмотреть, можно ли такое вообще запилить.</p><h2>Если хочешь поучаствовать</h2><ul><li><a href="https://t.me/Git_Gram/314" rel="nofollow">GitGram</a></li><li>Чат для хардкорных: <a href="http://t.me/sandbox_hardcore" rel="nofollow">@sandbox_hardcore</a> — вся сырая разработка, факапы и обсуждения (без цензуры)</li></ul><p>Подписывайся на мой <a href="https://t.me/+q0NBWy428y1hODEy" rel="nofollow">TГ-канал</a> — там я публикую все свои эксперименты, код и приглашаю к обсуждению. Только факты, мат и никакой политоты.</p>]]></content:encoded>
    </item>
    <item>
      <title>Бесплатный WAF инструмент кибербезопасности, который я использую</title>
      <link>https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu</link>
      <comments>https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Неопознанный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu</guid>
      <description><![CDATA[<p>Разбор бесплатного open-source WAF SafeLine для защиты от OWASP Top 10, DDoS и ботов. Сравнение с ModSecurity и Cloudflare по точности обнаружения атак, минимальные ложные срабатывания, простая установка одной командой Docker.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu">Бесплатный WAF инструмент кибербезопасности, который я использую</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Unity]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[IBM]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[Маркетинг]]></category>
      <category><![CDATA[CSR]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 01 Jul 2026 05:55:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Решения с открытым исходным кодом достигли такого уровня зрелости, что сегодня они действительно могут конкурировать с коммерческими продуктами — не только по функциональности, но и по удобству использования и поддержке сообщества. Если вы управляете собственной инфраструктурой, больше нет оправдания тому, чтобы оставлять дверь открытой для угроз.</p><p>SafeLine WAF — это бесплатный инструмент, который я лично тестировал.</p><p>Это полностью open-source решения, продукт с действительно бесплатной Community Edition, где ключевые функции не урезаны.</p><p><b>SafeLine WAF — веб-приложенийный межсетевой экран, который действительно поставляется с разумными настройками по умолчанию</b></p><p><b>Что он делает:</b></p><p>Защищает веб-приложения от SQL-инъекций, XSS-атак, командных инъекций, CSRF, SSRF, атак включения файлов и других угроз из списка OWASP Top 10. Также поддерживает защиту от CC/DDoS-атак, управление ботами и может работать как шлюз аутентификации.</p><p><b>Почему он:</b></p><p>Большинство WAF с открытым исходным кодом достаточно сложно настроить. Можно потратить часы на настройку правил, пытаясь остановить ложные срабатывания, из-за которых легитимные пользователи блокируются.</p><p>SafeLine использует другой подход — вместо того чтобы полностью полагаться на сигнатурное обнаружение, он применяет движок семантического анализа, который фактически анализирует и понимает входящие HTTP-запросы. Это позволяет добиться более высокого уровня обнаружения при значительно меньшем количестве ложных срабатываний по умолчанию.</p><p>Некоторые показатели, которые стоит учитыват</p><ol><li>Уровень обнаружения - SafeLine (Balanced) (71.65%), ModSecurity (Level 1) (69.74%), Cloudflare (Free) (10.7%)</li><li>Уровень ложных срабатываний - SafeLine (Balanced) (0.07%), ModSecurity (Level 1) (17.58%), Cloudflare (Free) (0.07%)</li><li>Точность - SafeLine (Balanced) (99.45%), ModSecurity (Level 1) (82.20%), Cloudflare (Free) (98.40%)</li></ol><p>Сбалансированный профиль SafeLine обнаруживает более 70% атак, при этом блокируя легитимный трафик ошибочно всего в 0.07% случаев. Это именно тот уровень настроек по умолчанию, который можно использовать в промышленной среде без постоянного ручного контроля.</p><p>Установка выполняется одной командой</p><p>После запуска он разворачивается как набор Docker-контейнеров: Tengine (форк Nginx) используется в качестве reverse proxy, отдельный сервис отвечает за семантический анализ, PostgreSQL хранит конфигурации и логи, а удобная веб-панель администратора работает на порту 9443.Community Edition поддерживает до 10 сайтов, чего достаточно для большинства личных проектов и небольших бизнес-сценариев.</p><p>Сайт: <a href="https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Fcodeby.net%2Fgoto%2Flink-confirmation%3Furl%3DaHR0cHM6Ly9jeWJlcnNlcnZhbC50ZWNoL2xhbmRpbmcvc2FmZWxpbmXvv7xHaXRIdWI%253D%26s%3D7008b60d8a0849ba0be350fe25edfa72&amp;postId=3005263" rel="nofollow noopener">https://cyberserval.tech/landing/safeline</a></p><p>GitHub:<a href="https://api.vc.ru/v2.8/redirect?to=http%3A%2F%2Fgithub.com%2Fchaitin%2FSafeLine&amp;postId=3005263" rel="nofollow noopener"> github.com/chaitin/SafeLine</a> (более 21 тыс. звёзд)</p><p>Лицензия: GPL-3.0 / MIT (Community Edition)</p>]]></content:encoded>
    </item>
    <item>
      <title>Как приручить legacy-код: безопасная модернизация без заморозки фич</title>
      <link>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</link>
      <comments>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[KODE]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</guid>
      <description><![CDATA[<p>Как модернизировать legacy-код без остановки продукта: Strangler Fig Pattern, feature flags, shadow testing и безопасная миграция данных. Практика и антипаттерны.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki">Как приручить legacy-код: безопасная модернизация без заморозки фич</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[ICO]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Twitter]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[OpenTelemetry]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[DeFi]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Техника]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 23 Jun 2026 06:16:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>Legacy-код — одна из самых болезненных тем в инженерных командах. Обычно все понимают, что система устарела: архитектура мешает быстро выпускать изменения, новые фичи приходится встраивать через обходные пути, тесты либо неполные, либо отсутствуют, а любое изменение в одном модуле неожиданно ломает другой.</p><p>Но при этом к такому коду часто боятся прикасаться. И не без причины. В старых системах редко бывает понятная карта зависимостей. Документация устарела, часть знаний живет только в головах нескольких разработчиков, а бизнес при этом продолжает ждать новых релизов, интеграций и продуктовых экспериментов.</p><p>Так появляется классическая ловушка legacy: систему надо модернизировать, но остановить развитие нельзя. Переписать всё с нуля страшно, поддерживать как есть — всё дороже. В результате продукт обрастает временными решениями, скорость разработки падает, а стоимость каждого следующего изменения растет.</p><p>Хорошая новость в том, что модернизация legacy-кода не обязана быть большим взрывом. Старую систему можно менять постепенно, сохраняя рабочий продукт, не замораживая фичи и не устраивая один критический релиз, от которого зависит всё.</p><h2>Почему Big Bang-переписывание чаще всего заканчивается плохо</h2><p>Когда команда долго живет с устаревшей системой, идея переписать всё с нуля выглядит очень соблазнительно. Кажется, что можно наконец избавиться от технического долга, выбрать нормальную архитектуру, перепроектировать модули, покрыть всё тестами и начать «правильно».</p><p>На старте такой план часто звучит логично. Особенно если текущая система действительно мешает развитию. Например, мобильное приложение растет, у него уже миллионы пользователей, бэкенд написан несколько лет назад как монолит, а каждая новая фича требует изменений в десятке мест. Команда устала чинить регрессии, бизнес устал ждать, и всем хочется «один раз нормально переписать».</p><p>Проблема не в самой идее переписывания, а в условиях, при которых оно проваливается. Большой риск возникает, когда совпадают четыре фактора: переписывание занимает много месяцев, в это время бизнес продолжает развивать старую систему, новая версия покрывает сразу большую часть функциональности, а откат связан с миграцией данных. Если все четыре пункта присутствуют, Big Bang почти гарантированно превратится в долгий и дорогой проект.</p><p>Допустим, команда решила переписать модуль заказов в e-commerce-продукте. В старой версии есть корзина, промокоды, доставка и оплата. Команда планирует за полгода сделать новый сервис заказов. Но за эти полгода бизнес добавляет подписки, подарочные сертификаты, частичную оплату бонусами и новую логику возвратов. В итоге новая система, которую проектировали под старые требования, к моменту релиза уже нуждается в доработке.</p><p>Есть и другая проблема: большой релиз почти всегда несет максимальный риск. Если вы заменяете крупный кусок системы целиком, ошибка влияет сразу на большую часть пользователей. Откат тоже становится сложным, потому что новая логика уже связана с новыми данными, контрактами и интеграциями.</p><p>Big Bang всё-таки бывает оправдан — но в узких условиях. Если кодовая база молодая (год-два), пользователей мало, у системы нет критичного состояния в БД и продукт можно временно заморозить или вести в обоих контурах параллельно, полное переписывание может оказаться дешевле постепенной миграции. Это редкая ситуация, и она быстро исчезает по мере роста продукта. В зрелых системах безопаснее работает другой подход — постепенная архитектурная эволюция.</p><h2>Пример: как команда переписала сервис документов и потеряла полгода</h2><p>Команда сопровождала сервис — старый модуль на aiohttp с Pydantic v1, через который проходила вся обработка путевых листов и актов осмотра транспорта. Сервис существовал шесть лет, был покрыт тестами фрагментарно, а его API использовали мобильное приложение водителей, диспетчерская веб-панель и пакетный импорт.</p><p>Команда решила переписать сервис целиком: перейти на FastAPI, обновить Pydantic до v2, заодно почистить контракты и заменить внутреннее хранилище документов с MongoDB на PostgreSQL. План был рассчитан на четыре месяца.</p><p>Через восемь месяцев проект всё ещё не был готов к выкатке, а к десятому месяцу команда откатила миграцию полностью. Причин было несколько.</p><p>Во-первых, переписывание шло параллельно с продуктовой разработкой. За время миграции бизнес добавил два новых типа документов и изменил правила подписи актов. Новая система проектировалась под старые требования и к моменту готовности уже не соответствовала продукту.</p><p>Во-вторых, команда не написала характеристических тестов. Поведение «как есть» нигде не было зафиксировано, и расхождения находились только в продакшене после переключения.</p><p>В-третьих, у старого сервиса были скрытые побочные эффекты, о которых никто не помнил. При смене статуса документа публиковал событие в Kafka, которое читал биллинг и сервис аналитики. В новой реализации это поведение не было воспроизведено, потому что в коде оно выглядело как «лишний» вызов. После переключения биллинг перестал получать события, и расхождение обнаружили только через две недели — по жалобе финансового отдела.</p><p>В-четвёртых, переключение было сделано «в лоб»: маршрут в API Gateway просто перенаправили на новый сервис. Фича-флага не было, теневого запуска не было, плана отката не было. Когда выяснилось, что новый сервис строже валидирует исторические форматы документов и отклоняет часть старых записей, быстро вернуться на старую реализацию не получилось — её к тому моменту уже отключили на стенде, а в БД успели уйти записи в новом формате.</p><p>В итоге миграцию свернули, потратив около десяти человеко-месяцев и потеряв доверие бизнеса. Сервис до сих пор работает в исходной реализации, а команда переходит к плану, описанному ниже.</p><h2>Strangler Fig Pattern: как заменить систему по частям</h2><p>Один из самых практичных подходов к модернизации legacy-кода — Strangler Fig Pattern. В софтверном виде паттерн был сформулирован Мартином Фаулером в 2004 году под названием StranglerFigApplication. Идея проста: не переписывать систему целиком, а постепенно выносить отдельные части в новую реализацию.</p><p>Название пришло из биологии. Фикус-душитель растет вокруг дерева-хозяина и постепенно вытесняет его. В архитектуре принцип похожий: старая система продолжает работать, новая функциональность появляется рядом, а затем отдельные потоки постепенно переводятся на новую реализацию.</p><p>Представим старый монолит интернет-магазина. Внутри него есть каталог, корзина, заказы, платежи, скидки, личный кабинет и уведомления. Переписать всё сразу — рискованно. Но можно начать с относительно изолированного участка, например с уведомлений.</p><p>Сначала команда описывает текущий контракт: какие события приходят в модуль уведомлений, какие каналы используются, какие шаблоны отправляются, какие ошибки считаются допустимыми. Затем рядом создается новый сервис уведомлений, который реализует тот же контракт. На первом этапе он может даже не отправлять реальные сообщения, а только принимать события и логировать результат. После проверки часть трафика переводится на новую реализацию. Когда сервис стабилизируется, старый код уведомлений удаляется из монолита.</p><p>Strangler Fig хорошо работает там, где между старым и новым кодом есть сетевая граница: HTTP, message bus, RPC. Если такой границы нет — например, нужно постепенно заменить функцию или класс внутри одного процесса — используется родственный паттерн Branch by Abstraction: над старой реализацией создается абстракция, рядом пишется новая реализация, переключение происходит через конфигурацию или фича-флаг, после стабилизации старая ветка удаляется. Снаружи это выглядит как Strangler Fig, но без сетевого прокси.</p><p>Такой подход снижает риск. В системе нет одного большого релиза, где всё меняется сразу. Есть серия небольших контролируемых изменений. Каждое можно протестировать, измерить и откатить.</p><h2>Главное правило: сначала повторить поведение, потом улучшать</h2><p>Одна из частых ошибок при модернизации legacy-кода — попытка одновременно переписать систему и улучшить бизнес-логику. Команда смотрит на старый модуль и думает: «Раз уж мы его трогаем, давайте сразу сделаем нормальную архитектуру, изменим контракты, уберем странные кейсы и перепишем поведение».</p><p>Это опасный путь. В legacy-системах странное поведение часто существует не случайно. За ним может стоять неочевидное бизнес-правило, старый клиент, интеграция с внешней системой или исторический баг, на который уже кто-то завязался.</p><p>Например, в системе расчета налогов может быть правило: для контрактов, заключенных до 2018 года, НДС округляется в меньшую сторону до целого рубля, а для всех остальных — по математическим правилам. Новый разработчик может решить, что это ошибка, и «исправить» округление. Но потом выяснится, что часть крупных клиентов держит это поведение в своих сверках, а смена правила приведет к расхождениям в актах и претензиям.</p><p>Прежде чем менять поведение, его нужно зафиксировать. Для этого пишут характеристические тесты (characterization tests, иногда называемые golden master или approval tests). Идея простая: на реальных данных или их обезличенных копиях прогоняется старая реализация, её ответы сохраняются как эталон, и любые будущие изменения, отклоняющиеся от эталона, отлавливаются автоматически. Тесты пишутся не для красоты, а для того, чтобы зафиксировать существующее поведение — даже странное — перед тем, как его трогать. Подробно эта техника описана у Майкла Физерса в книге Working Effectively with Legacy Code; на практике её удобно реализовать через библиотеки семейства approval-tests (approvaltests-python, approvaltests-java и аналоги).</p><p>Поэтому первый этап модернизации — не улучшение, а воспроизведение текущего поведения. Новая реализация должна вести себя так же, как старая. Даже если старое поведение кажется странным. Только после стабилизации можно отдельно обсуждать, что именно стоит менять.</p><h2>Feature toggles: как включать новую логику без риска</h2><p>Feature toggles, или фича-флаги, — один из главных инструментов безопасной миграции. Они позволяют включать и выключать новую логику без деплоя.</p><p>В обычной разработке релиз часто выглядит бинарно: код либо выкатили, либо нет. При миграции legacy это неудобно. Гораздо безопаснее иметь возможность включить новую реализацию для 1% пользователей, затем для 10%, потом для половины аудитории и только после этого для всех.</p><p>Например, команда переносит расчет стоимости доставки из монолита в новый сервис. С помощью фича-флага это выглядит так:</p><p>user_id передается явно, чтобы решение «попал ли пользователь в новый сегмент» было стабильным от запроса к запросу. Иначе один и тот же клиент будет получать разные ответы при обновлении страницы, и поведение системы станет непредсказуемым.</p><p>На первом этапе флаг включают только для внутренней команды. Потом для тестового сегмента пользователей. Затем для небольшой доли реального трафика. Если метрики стабильны, долю увеличивают. Если появляются ошибки, флаг выключают, и пользователи снова идут в старую реализацию.</p><p>Важно различать два разных типа флагов. Флаг постепенной выкатки (rollout flag) меняется редко и контролирует, какой процент пользователей видит новую логику. Kill switch — отдельный флаг, единственная задача которого — мгновенно выключить новую реализацию при инциденте. Kill switch должен опрашиваться на каждом запросе, его кэширование должно жить секунды, а не минуты, и он принципиально не должен зависеть от той системы, которую он выключает. Иначе в момент аварии может оказаться, что выключатель сам недоступен.</p><p>В качестве инфраструктуры для флагов команды обычно берут одну из платформ: LaunchDarkly, Unleash, Flagsmith, GrowthBook, либо собирают собственную поверх Redis или конфигурационного сервиса. Для миграции важны три свойства: быстрое распространение изменений (секунды, а не минуты), поддержка таргетинга по пользователю/сегменту и аудит — кто и когда менял флаг.</p><p>Важно, что фича-флаг — это не просто if в коде. Для серьезной миграции нужны правила: кто может включать флаг, как быстро его можно отключить, какие метрики отслеживаются, когда флаг должен быть удален.</p><p>Последний пункт особенно важен. Если флаги не удалять, система быстро превращается в набор ветвлений, где никто уже не понимает, какая логика актуальна.</p><h2>Shadow testing: как проверить новую систему на реальном трафике</h2><p>Feature toggles помогают безопасно переключать пользователей. Но перед этим хорошо бы понять, совпадает ли новая логика со старой. Для этого используют shadow testing.</p><p>Shadow testing — это запуск новой реализации параллельно старой, но без влияния на пользователя. Пользовательский запрос по-прежнему обрабатывает старая система, а новая получает копию запроса и считает результат «в тени». Пользователю этот результат не показывается. Команда только сравнивает ответы.</p><p>Например, есть старый модуль расчета скидок. Он учитывает промокоды, сегмент пользователя, историю покупок, регион и партнерские условия. Команда пишет новый сервис скидок. Чтобы не переключать пользователей сразу, можно запустить теневой режим:</p><p>Два момента, на которые стоит обратить внимание в этом коде. Теневой вызов запускается через asyncio.create_task — корутина сразу планируется в event loop и начнёт выполняться, как только функция вернёт управление. И весь блок завернут в try/except: исключение в новой логике не должно ронять основной запрос. Без этих двух свойств shadow testing рискует ухудшить продакшен вместо того, чтобы безопасно его проверить.</p><p>Небольшая оговорка для продакшена: event loop держит на task только слабую ссылку, и без сохранённой ссылки задача может быть собрана сборщиком мусора прямо во время выполнения. В реальном коде Task имеет смысл класть в set фоновых задач и удалять оттуда через add_done_callback. В примере выше эта обвязка опущена для читаемости.</p><p>Для критичной доменной логики — платежей, биллинга, расчета тарифов — допустимый уровень расхождения должен быть около нуля: цель в shadow-режиме не «как можно меньше различий», а «понимаем каждое расхождение». Для менее чувствительных доменов (рекомендации, ранжирование результатов поиска) можно жить с расхождением в долях процента, но и там расхождения нужно классифицировать, а не игнорировать. Возможно, это баги новой реализации. А возможно, старая система содержит устаревшую логику, которую нужно отдельно обсудить с бизнесом.</p><p>Shadow testing особенно полезен для критичных доменных частей: платежей, биллинга, расчета тарифов, персональных предложений, транзакций. Там нельзя просто «попробовать на пользователях» и посмотреть, что будет.</p><p>При этом важно отличать теневую проверку чтения от теневой проверки записи. Чтение проверить относительно дёшево: запрос идёт в обе системы, ответы сравниваются, никаких внешних эффектов нет. С записью всё сложнее. Если новая реализация в shadow-режиме действительно создаст заказ, спишет деньги или отправит письмо, у пользователя возникнут двойные эффекты. Поэтому для writes либо вводят идемпотентные ключи и shadow-режим без реальных побочных действий (внешние вызовы заменены no-op-стабами, БД — отдельной shadow-копией), либо вообще отказываются от теневой проверки записи в пользу постепенной выкатки за фича-флагом.</p><p>Сравнение ответов в реальной системе тоже не сводится к одной функции compare. Нужно отдельно решать, как игнорировать «нормальный» шум (метки времени, идентификаторы, порядок коллекций), как сэмплировать трафик, чтобы не утопить хранилище расхождений, и как организовать триаж — кто и в каком ритме разбирает накопившиеся диффы. Готовые решения этого класса — GitHub Scientist (Ruby и его порты в другие языки), Twitter Diffy, либо собственный лёгкий регистратор поверх Kafka и таблицы расхождений.</p><h2>С чего начинать модернизацию</h2><p>Начинать лучше не с самого больного и не с самого центрального модуля. Это звучит контринтуитивно, потому что обычно хочется сразу взяться за главный источник проблем. Но если начать с ядра системы, команда быстро упрется в максимальное количество зависимостей и рисков.</p><p>Удобный способ выбрать первый кусок — оценить кандидатов по двум осям: насколько модуль критичен для бизнеса (low / high) и насколько сильно он связан с остальной системой (low / high). Начинать стоит с квадранта low-criticality + low-coupling: ошибки в нем не уронят бизнес-показатели, а малое количество зависимостей позволит провести миграцию полностью, не утянув за собой смежные модули. Высоко-критичные и сильно связанные части (платежи, ядро авторизации) трогают в последнюю очередь — на этот момент команда уже наберёт опыт безопасной миграции.</p><p>Хорошие точки входа обычно: уведомления, генерация отчетов, поиск, история операций, профиль пользователя, отдельная часть каталога. Важно, чтобы у команды была возможность описать контракт: какие данные входят, какие выходят, какие ошибки возможны, какие внешние системы участвуют.</p><p>Допустим, в банковском приложении есть старый модуль истории операций. Он медленный, сложно расширяется, но при этом не выполняет сами транзакции. Это хороший кандидат для первой миграции. Ошибка в истории операций неприятна, но обычно менее критична, чем ошибка в списании денег.</p><p>Команда может вынести чтение истории в отдельный сервис, сначала запустить его в shadow-режиме, потом включить для части пользователей, затем полностью перевести чтение на новую реализацию. При этом критичная транзакционная логика останется в старой системе до тех пор, пока команда не наберет опыт безопасной миграции.</p><h2>Миграция данных: самая сложная часть</h2><p>Большая часть статьи говорит о маршрутизации запросов и переключении трафика. Но в реальных проектах основная сложность лежит ниже — в данных. Старая и новая реализации почти всегда работают с общим состоянием: одной БД, одним хранилищем документов, одним набором очередей. Переехать туда «одним коммитом» нельзя.</p><p>Базовый рабочий приём — Expand-Contract (он же Parallel Change). Изменение схемы делается в три такта. На этапе expand в БД добавляются новые поля, таблицы или индексы, при этом старое поведение полностью сохраняется. Затем — migrate: обе реализации начинают писать и в старое, и в новое место (dual writes), а отдельный фоновый процесс делает backfill — заполняет новые поля историческими данными. После этого читатели по одному переключаются на новую схему. Только когда никто из читателей не использует старую структуру, наступает contract — удаление лишних колонок и таблиц.</p><p>Несколько практических деталей, которые часто упускают:</p><p>·         Dual writes — это не бесплатная операция. Две записи означают две точки отказа. Если одна из них упала, нужно решать, что делать: продолжать ли работу, ставить ли событие в очередь на повтор, помечать ли запись как несогласованную. Простое «сначала пишем туда, потом сюда» в продакшене на нагрузке приводит к расхождениям.</p><p>·         Backfill часто длиннее, чем кажется. На большой таблице миграция в одном UPDATE блокирует продакшен. Поэтому backfill делают батчами по N тысяч строк с паузами, отслеживают прогресс и предусматривают возможность остановить и продолжить.</p><p>·         Онлайн-изменения схемы на крупных таблицах делаются не штатным ALTER TABLE, а специализированными инструментами: gh-ost или pt-online-schema-change для MySQL, встроенные онлайн-механизмы PostgreSQL для индексов и колонок, Liquibase/Flyway — для управления версионированием изменений в репозитории.</p><p>·         Shadow testing данные не покрывает. Можно сравнить, что новая реализация возвращает то же, что и старая, но если за этим стоит другая схема в БД, проверка корректности самой миграции данных — это отдельная работа: сверки, контрольные суммы, выборочный аудит исторических записей.</p><p>Без этих шагов любая красивая фасадная архитектура наталкивается на разъезжающиеся данные — и тогда даже идеальный Strangler Fig снаружи не спасает.</p><h2>Прокси-слой как точка контроля</h2><p>Чтобы постепенно заменять legacy-код, нужно управлять маршрутизацией запросов. Для этого часто создают прокси-слой, API Gateway или фасад, через который проходит обращение к старой и новой логике. В терминах Domain-Driven Design такой слой часто называют Anti-Corruption Layer: он защищает новую реализацию от старых контрактов и наоборот, позволяя двум моделям сосуществовать без взаимного «загрязнения».</p><p>Без такой точки контроля миграция становится хаотичной. Часть клиентов ходит напрямую в старый модуль, часть — в новый, часть использует обходные пути, а команда теряет возможность централизованно переключать трафик.</p><p>Прокси-слой решает несколько задач. Он скрывает детали реализации от клиентов, позволяет направлять часть запросов в новую систему, поддерживает фича-флаги, собирает метрики и упрощает откат.</p><p>В качестве технической основы команды обычно берут один из трех вариантов: классический API gateway (Kong, AWS API Gateway), service mesh (Envoy, Istio) или более простой reverse proxy (NGINX, HAProxy). Service mesh особенно удобен, когда трафик уже идёт внутри Kubernetes-кластера: маршрутизацию можно менять конфигурацией, без правок кода клиентов и сервисов.</p><p>Например, мобильное приложение обращается к endpoint /orders/history. Раньше этот endpoint напрямую обслуживал монолит. После введения API Gateway приложение продолжает ходить по тому же контракту, но внутри gateway может решать, куда направить запрос: в legacy-модуль или новый сервис истории заказов.</p><p>Управление маршрутизацией обычно делается не «всё или ничего», а на основании атрибутов запроса: значения заголовка (X-Migration-Cohort: new), куки, хэша от user-id (стабильное разбиение пользователей на сегменты) или географического региона. Это позволяет выкатывать новую реализацию сначала на одну страну, на сотрудников самой компании или на тестовый сегмент — и только потом расширять охват.</p><p>Для клиента ничего не меняется. Для команды появляется управляемость.</p><h2>Наблюдаемость: без метрик миграция превращается в гадание</h2><p>Постепенная модернизация невозможна без нормальной наблюдаемости. Если команда не видит, что происходит внутри системы, она не сможет безопасно переключать трафик.</p><p>Минимальный набор — это логи, метрики и распределенная трассировка (distributed tracing). Нужно понимать, сколько запросов идет в старую и новую реализацию, сколько ошибок возникает, как меняется latency, где появляются таймауты, какие статусы возвращаются, какие бизнес-метрики проседают.</p><p>Технические метрики стоит формулировать не как «средний ответ» и «процент ошибок», а в терминах SLI и SLO: целевые показатели вида «99.9% запросов на /orders/history отвечают быстрее 300 ms за 30 дней» с явным error budget. Latency измеряется по перцентилям (p50, p95, p99) — среднее значение почти всегда обманчиво, а хвосты распределения говорят о реальном опыте пользователя. На время миграции имеет смысл выставить отдельные SLO для нового и старого пути и сравнивать их.</p><p>В качестве инструментов де-факто стандартом стал OpenTelemetry для трассировок, метрик и логов — единый протокол, который пишет в практически любое хранилище. Дальше — Prometheus и Grafana для метрик, Jaeger или Tempo для traces, Sentry или аналог для ошибок. Для миграции важна возможность фильтровать метрики по «варианту» — отдельно по старому и новому пути — иначе все цифры смешаются и реальную динамику будет не видно.</p><p>Технических метрик недостаточно. Если команда переносит оформление заказа, важно смотреть не только на 500 ошибки и время ответа, но и на конверсию в оплату, количество брошенных корзин, повторы запросов, обращения в поддержку.</p><p>Пример: новая система формально отвечает быстрее старой и не дает ошибок. Но после включения на 10% пользователей падает конверсия в оплату. Причина может быть не в серверной ошибке, а в изменении порядка полей, другом тексте сообщения или потере какого-то edge-case. Без бизнес-метрик команда может решить, что миграция успешна, хотя для продукта она уже создает проблему.</p><h2>Практическая последовательность миграции</h2><p>Рабочая последовательность обычно выглядит так.</p><p>Сначала команда выбирает ограниченный участок системы. На этом этапе важно не просто назвать модуль, а описать его границы. Какие сценарии он закрывает? Кто его вызывает? Какие данные он читает и пишет? Какие внешние интеграции использует? Какие неочевидные бизнес-правила в нем есть?</p><p>Затем поверх legacy-логики создается стабильный контракт. Это может быть API, фасад, gateway или отдельный слой внутри приложения. Главная задача — сделать так, чтобы клиенты зависели не от внутренней реализации, а от понятного интерфейса. На этом этапе полезно вспомнить про contract testing (Pact, Spring Cloud Contract): автотесты со стороны потребителей фиксируют, что именно они ожидают от API, и предупреждают о ломающих изменениях до того, как они доедут до продакшена.</p><p>После этого рядом пишется новая реализация. Она должна повторять текущее поведение, а не сразу становиться «идеальной версией будущего». На этом этапе полезно фиксировать все расхождения: где старая система работает странно, где требования не описаны, где бизнес-правила требуют уточнения.</p><p>Следующий этап — shadow testing. Новая система получает копии реальных запросов, считает результат, но пользователю по-прежнему возвращается ответ legacy. Команда сравнивает результаты и устраняет расхождения.</p><p>Когда новая реализация достаточно стабильна, начинается постепенное переключение через feature toggles. Сначала внутренние пользователи, потом 1% реального трафика, затем 5–10%, затем 50% и только после этого 100%.</p><p>На каждом этапе команда смотрит на метрики. Если всё стабильно, движение продолжается. Если появляются проблемы, флаг выключается, трафик возвращается в legacy, а команда разбирает причины.</p><p>Последний этап — удаление старого кода. Это не формальность, а обязательная часть миграции. И «удалить старый код» — это не один коммит, а явный Definition of Done: вырезана старая ветка кода, удалён фича-флаг, обновлена документация и схемы архитектуры, переименованы или удалены устаревшие дашборды и алерты, обновлены runbook’и для on-call и проведено короткое внутреннее обучение. Если этого не сделать, через полгода никто уже не вспомнит, какой путь актуален, и легаси-ветвление останется в коде навсегда.</p><h2>Откат миграций: дешёвый только пока не пошли записи</h2><p>Откатить миграцию, в которой ещё не было записи в БД, легко: достаточно переключить фича-флаг, и трафик снова идёт через старую реализацию. Откатить миграцию, в которой новая система уже неделю писала данные в новые таблицы, — отдельный, гораздо более тяжёлый разговор.</p><p>Поэтому ещё на этапе проектирования каждое изменение должно сопровождаться явным планом отката. Удобно различать три типа шагов.</p><p>Полностью обратимые шаги. Чтение через новый сервис, расчёт «в тени», новые метрики. Откат — выключить флаг. Это самый комфортный режим, и в нём стоит держать миграцию как можно дольше.</p><p>Обратимые с компенсацией. Новая реализация пишет дополнительные данные (например, дублирует операции в новую таблицу), но старый источник тоже обновляется. Откат возможен, но требует решить, что делать с уже записанными данными: оставить, очистить, синхронизировать. План этих действий должен быть написан до выкатки, не во время инцидента.</p><p>Forward-only. После некоторой точки откат становится невозможен — например, после того, как старая схема удалена или внешние интеграции перенастроены на новый сервис. Такие шаги допустимы, но к ним нужно приходить отдельно, осознанно, с особенно строгими SLO в предыдущем этапе. До forward-only-перехода имеет смысл подержать систему в режиме параллельной работы дольше, чем по графику.</p><p>Базовое правило: ни один шаг миграции не должен уходить в продакшен, если у команды нет письменного ответа на вопрос «как мы откатываемся в случае проблемы». Иначе при инциденте откатываться будут на ходу — и не факт, что успешно.</p><h2>Пример: как тот же сервис мигрировали со второй попытки</h2><p>После неудачного опыта команда взялась за тот же сервис заново, но изменила подход.</p><p>На первом шаге они зафиксировали поведение существующего сервиса. На самые часто используемые сценарии (создание путевого листа, подпись акта осмотра, выгрузка пакета документов за период) написали характеристические тесты на реальных продакшен-данных, обезличенных и сохранённых как фикстуры. Любое будущее изменение поведения теперь падало в CI как явное расхождение.</p><p>Параллельно команда провела инвентаризацию побочных эффектов. Из исходного кода и логов выяснилось, что сервис не только хранит документы, но и: публикует событие в Kafka при смене статуса, инкрементирует счётчик в Redis для рейтинга водителей, отправляет webhook во внешнюю систему партнёра, пишет в таблицу аудита. Каждый из этих эффектов попал в отдельный пункт чек-листа «что должно остаться» в новой реализации.</p><p>Затем команда выбрала первый кусок для выноса — не весь сервис, а только чтение документов (GET /documents/{id} и GET /documents/by-driver/{driver_id}). Это была наименее рискованная часть: ошибки в чтении неприятны, но не ломают финансовые потоки.</p><p>Новый сервис написали на FastAPI рядом со старым. На уровне API Gateway появилось правило маршрутизации: запросы на чтение шли в старый сервис, но в фоне дублировались в новый. Ответ пользователю всегда возвращал legacy, а ответ нового сервиса сравнивался с эталоном и записывался в отдельную таблицу для разбора. Использовали обёртку поверх asyncio.create_task — на ответ пользователя теневой вызов не влиял.</p><p>За три недели shadow-режима команда нашла четыре расхождения. Два оказались багами новой реализации (округление времени, неправильная сортировка вложений). Два — давно забытыми особенностями старого сервиса (одно поле возвращалось в UTC, другое — в локальной зоне; так было исторически, бизнес не возражал, но в новой реализации захотели единый формат). Все четыре зафиксировали явно: баги — починили, особенности — согласовали с продуктовой командой как осознанное изменение.</p><p>Когда расхождений не осталось, включили фича-флаг на сотрудников самой компании. Через неделю — на 1% реальных водителей. Дальше шаг по 5%, 25%, 50%, 100% с паузой в несколько дней между этапами. На каждом шаге следили не только за HTTP-ошибками и latency, но и за продуктовыми метриками: количество подписанных актов, время от открытия документа до подписи, доля повторных запросов. Один раз пришлось откатиться с 25% на 5% — в одном из регионов выросло время отклика из-за неэффективного запроса. Исправили, выкатили снова.</p><p>Через два месяца чтение полностью перешло в новый сервис. Старый код чтения и фича-флаг удалили в том же релизе. После этого по той же схеме мигрировали запись документов, потом публикацию событий, потом импорт из внешних систем. Полная миграция заняла девять месяцев — почти столько же, сколько провалившийся Big Bang, — но продукт всё это время продолжал развиваться, инцидентов не было, и в конце команда осталась с системой, которую понимает.</p><h2>Типичные ошибки при работе с legacy</h2><p>Первая ошибка — пытаться улучшить всё сразу. Команда одновременно меняет архитектуру, бизнес-логику, контракты и инфраструктуру. В результате становится невозможно понять, какая именно часть вызвала проблему. Правильнее сначала воспроизвести поведение, стабилизировать новую реализацию и только потом улучшать.</p><p>Вторая ошибка — недооценивать скрытые зависимости и побочные эффекты. Legacy-код часто делает больше, чем кажется. На один и тот же вызов могут быть навешаны: запись в таблицу аудита, инкремент счётчика в кэше, публикация события в очередь, обновление статуса связанной сущности, инвалидация кэша, дёрганье webhook’а во внешнюю систему. Если в новой реализации воспроизвести только явный путь, скрытые потребители молча перестанут получать данные — и узнают об этом через жалобу бизнеса, а не через ошибку в логах. Поэтому перед выносом любого модуля имеет смысл составить инвентаризацию побочных эффектов: пройтись по коду и логам и выписать каждое нелогичное действие отдельным пунктом чек-листа.</p><p>Третья ошибка — отсутствие наблюдаемости. Без логов, метрик и трассировки команда не управляет миграцией, а угадывает. Особенно опасно смотреть только на технические ошибки и игнорировать бизнес-показатели.</p><p>Четвертая ошибка — не договариваться с бизнесом. Модернизация не должна быть невидимой «инженерной активностью в стол». Её нужно встраивать в roadmap, объяснять эффект и договариваться о приоритетах. Если бизнес не понимает, зачем команда тратит время на миграцию, работа будет постоянно проигрывать новым фичам.</p><p>Пятая ошибка — не удалять старый код. Временное сосуществование старой и новой логики нормально. Вечное сосуществование — нет. Если legacy не удаляется, технический долг не уменьшается, а просто меняет форму.</p><p>Шестая ошибка — не удалять фича-флаги после миграции. Флаг, который сыграл свою роль и больше никогда не выключается, превращается в постоянное ветвление в коде. Через год команда не помнит, можно ли удалить такую ветку или там сидит важный edge-case. Через два — кода с такими «мёртвыми» флагами становится больше, чем основной логики. Поэтому каждый флаг должен заводиться с условием удаления («после полной выкатки и двух недель стабильной работы») и иметь ответственного, кто этим удалением займётся.</p><p>Отдельно стоит упомянуть организационную сторону. Закон Конвея работает и в обратную сторону: если новый и старый код владеются разными командами с разными приоритетами, миграция будет тормозиться независимо от выбранного паттерна. На время миграции имеет смысл явно проговорить, кто отвечает за переход, и не разделять старую и новую реализации между несовместимыми roadmap’ами.</p><h2>Компромиссы, к которым нужно быть готовыми</h2><p>Постепенная модернизация безопаснее Big Bang-переписывания, но она не бесплатна. Некоторое время система будет сложнее, чем раньше. В ней появятся старый и новый код, прокси-слой, фича-флаги, дублирование логики, дополнительные метрики.</p><p>Shadow testing увеличит нагрузку на инфраструктуру, потому что часть запросов будет обрабатываться дважды. Команде придется поддерживать дисциплину: документировать контракты, отслеживать флаги, удалять старую реализацию после миграции, поддерживать contract-тесты в актуальном состоянии.</p><p>Но это контролируемая сложность. Она распределена во времени и управляется инженерными практиками. В отличие от Big Bang-риска, где команда долго работает с минимальной обратной связью, а потом выкатывает один большой релиз с максимальной неопределенностью.</p><h2>Когда Strangler Fig особенно оправдан</h2><p>Постепенная миграция особенно хорошо подходит для систем, где downtime невозможен или слишком дорог. Это финтех, e-commerce, биллинг, мобильные бэкенды с большой аудиторией, высоконагруженные продукты, старые монолиты и системы с большим количеством интеграций.</p><p>Если продуктом ежедневно пользуются сотни тысяч или миллионы людей, нельзя позволить себе «переписать и посмотреть, что будет». Нужно менять архитектуру так, чтобы пользователь не замечал процесса миграции.</p><p>Этот подход также полезен там, где бизнес продолжает активно развивать продукт. Если фичи нельзя заморозить на полгода, модернизация должна идти параллельно с продуктовой разработкой.</p><h2>Когда модернизацию лучше не делать</h2><p>Постепенная миграция — мощный инструмент, но у неё тоже есть стоимость, и иногда правильный ответ — оставить систему как есть. Несколько сценариев, в которых модернизация плохо окупается.</p><p>Продукт, который уходит из эксплуатации. Если через год сервис будет выключен или заменён на покупное решение, тратить квартал на его рефакторинг бессмысленно. Достаточно стабилизировать то, что есть.</p><p>Модуль, который никто не трогает. Если код десятилетней давности продолжает работать, не падает, не требует изменений и не вызывает инцидентов, его «уродливость» — не повод его переписывать. Цель модернизации — упростить будущие изменения; если будущих изменений нет, цели тоже нет.</p><p>Регулируемые системы с тяжёлой ресертификацией. В банковских, медицинских и государственных контурах любое изменение в критичной системе может потребовать повторной сертификации, перепрохождения аудитов, обновления договорной обвязки. В таких условиях стоимость модернизации может на порядок превышать стоимость поддержки текущей реализации, и решение нужно принимать вместе с владельцем продукта и юристами, а не только инженерным составом.</p><p>Простой тест: если на вопрос «какой бизнес-сценарий мы откроем после миграции» нет внятного ответа — модернизацию имеет смысл отложить и заняться чем-то другим.</p><h2>Что получает команда</h2><p>Главный результат постепенной модернизации — управляемость. Команда начинает лучше понимать систему, контролировать изменения и снижать риск инцидентов.</p><p>Появляются понятные контракты, наблюдаемость, практика безопасных релизов, культура удаления старого кода. Разработчики перестают бояться legacy, потому что у них появляется метод, а не только желание «когда-нибудь всё переписать».</p><p>Для бизнеса это тоже выгодно. Продукт продолжает развиваться, сроки становятся более прогнозируемыми, риски крупных сбоев снижаются, а технический долг постепенно уменьшается.</p><h2>Модернизация — это процесс, а не проект</h2><p>Legacy нельзя «починить за квартал». Если система развивалась годами, она не станет простой после одного рефакторинга. Но её можно системно улучшать.</p><p>Strangler Fig Pattern, Branch by Abstraction, feature toggles, shadow testing и аккуратная миграция данных дают рабочую модель: выбрать ограниченный участок, описать контракт, реализовать новую версию, проверить её на реальном трафике, постепенно переключить пользователей и удалить старый код.</p><p>Это не самый быстрый путь. Зато он управляемый. А в зрелых продуктах управляемость важнее скорости.</p><p>Потому что цель модернизации — не написать красивую новую систему. Цель — сделать так, чтобы продукт продолжал развиваться, команда могла безопасно вносить изменения, а пользователи не становились участниками инженерного эксперимента.</p>]]></content:encoded>
    </item>
    <item>
      <title>Что такое Git worktrees и зачем их использовать</title>
      <link>https://tproger.ru/translations/chto-takoe-git-worktrees-i-zachem-ih-ispolzovat</link>
      <comments>https://tproger.ru/translations/chto-takoe-git-worktrees-i-zachem-ih-ispolzovat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/chto-takoe-git-worktrees-i-zachem-ih-ispolzovat</guid>
      <description><![CDATA[<p>Git worktrees появились ещё в 2015 году, но популярность обрели только недавно. Разбираем, что это такое, как использовать в терминале и зачем они пригодятся.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/chto-takoe-git-worktrees-i-zachem-ih-ispolzovat">Что такое Git worktrees и зачем их использовать</a>»</p>]]></description>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Инструменты командной строки]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 18 Jun 2026 03:00:07 GMT</pubDate>
      <content:encoded><![CDATA[<p>Перевод статьи Cassidy Williams из GitHub Blog, оригинал: <a href="https://github.blog/ai-and-ml/github-copilot/what-are-git-worktrees-and-why-should-i-use-them/">https://github.blog/ai-and-ml/github-copilot/what-are-git-worktrees-and-why-should-i-use-them/</a></p><p>Git worktrees позволяют держать несколько рабочих копий одного репозитория на разных ветках — и сейчас эта возможность в тренде. Забавно, что в Git она появилась ещё в 2015 году. Но worktrees действительно удобны, и в этой статье разберёмся, зачем они нужны, чем отличаются от обычных веток и почему внезапно стали популярны.</p><p>worktree — это дополнительная рабочая копия репозитория на другой ветке, привязанная к тому же .git.</p><p>С их помощью можно переключаться между задачами, не прерывая текущую работу и не используя stash.</p><p>Они особенно полезны при параллельной работе с ИИ-агентами и в приложении GitHub Copilot.</p><p>У worktrees есть ограничения: раздувание зависимостей, необходимость убирать папки, правила .gitignore и запрет на одновременный checkout одной ветки в нескольких worktrees.</p><h2>Переключение контекста через ветки и stash</h2><p>Представьте: вы работаете над задачей и вдруг получаете срочный баг. Нужно срочно переключить контекст.</p><p>Сначала, скорее всего, спрячете текущие изменения в stash:</p><p>Потом перейдёте на main и обновите её:</p><p>Затем создадите ветку с хотфиксом:</p><p>Пофиксите, закоммитите и запушите ветку:</p><p>После слияния pull request вы вернётесь к компьютеру, подтянете main и удалите ветку с багфиксом:</p><p>А потом сможете вернуться к задаче, над которой работали:</p><p>Фух. На чём мы остановились?</p><p>Переключение туда-сюда, перезагрузка файлов, переустановка node_modules в зависимости от того, что изменилось, — всё это отнимает много сил. Нагрузка от смены контекста серьёзная.</p><p>Это базовый пример, но иногда разработчики справлялись с таким хаосом сложными командами git stash или даже несколькими клонами одного репозитория (я сама грешила этим).</p><p>А потом появились… worktrees!</p><h2>Переключение контекста через worktrees</h2><p>С worktrees вы никогда не покидаете свою ветку и не используете stash, а редактор с вашей текущей фичей остаётся нетронутым.</p><p>Эта команда мгновенно создаёт соседнюю папку hotfix-workspace, базирует её на main и создаёт новую ветку hotfix-bug.</p><p>Теперь можно открыть эту папку в новом окне редактора (или перейти в неё через cd) и чинить баг. Исходное окно редактора остаётся в том же состоянии, в котором вы его оставили.</p><p>Pull request сливаете онлайн, как обычно, а после слияния можно просто удалить временную папку.</p><p>Гораздо плавнее! Нет риска конфликтов stash, редактор не перезагружается, и вы действительно можете работать параллельно.</p><h2>Так почему же сейчас?</h2><p>Долгое время worktrees были относительно неизвестны. Большинство разработчиков никогда о них не слышали, потому что либо Git GUI не поддерживали их (или относились как к второсортной функции), либо все привыкли к знакомой схеме: feature-ветка, работа, PR, merge и повтор.</p><p>Сейчас наша работа изменилась. ИИ заставляет нас работать параллельно больше, чем когда-либо в истории разработки ПО. Разработчики запускают множество сессий одновременно, а «культура код-ревью» растёт быстрее, чем «культура написания кода».</p><p>Агенты и люди могут делать больше параллельно с помощью worktrees. Это режим по умолчанию в приложении GitHub Copilot и во многих других современных инструментах.</p><blockquote>Агенты и люди могут делать больше параллельно с помощью worktrees.</blockquote><h2>В чём подвох?</h2><p>Worktrees решают кучу проблем, но есть нюансы, на которые стоит обращать внимание.</p><ul><li>Раздувание зависимостей: каждая папка worktree требует собственную копию зависимостей проекта. Если запускать npm install или pip install в нескольких worktrees, диск может быстро закончиться.</li><li>Управление папками: нужно удалять папки worktree, чтобы со временем не засорять родительский каталог. Приложение GitHub Copilot часто делает это за вас, но если вы работаете в терминале, придётся следить самостоятельно.</li><li>Требования к глобальному .gitignore: если создавать worktree внутри основного репозитория, их нужно вручную добавить в .gitignore, чтобы случайно не закоммитить. Можно создавать worktree за пределами основного репозитория (GitHub Copilot делает это по умолчанию), но это стоит учитывать.</li><li>Ограничение «одна ветка»: Git не позволяет одновременно checkout’ить одну и ту же ветку в двух разных worktrees, чтобы избежать повреждения данных.</li></ul><h2>Как использовать git worktrees в приложении GitHub Copilot?</h2><p>Отличный вопрос! Здорово, что там всё работает «из коробки». Когда вы открываете приложение, на главном экране есть выпадающий список, который спрашивает, где запускать новую сессию. По умолчанию выбран новый worktree.</p><p>Когда вы запускаете новую сессию, можно нажать на имя сессии вверху приложения и увидеть (забавное!) сгенерированное имя вашего worktree, а также путь, где он находится, проект, для которого он создан, и сведения о внесённых изменениях.</p><p>Проще простого!</p><h2>Стоит ли использовать worktrees?</h2><p>Я дам вам самый senior-ответ, который только можно: зависит от ситуации! Вам может быть удобнее работать по-другому. Возможно, вы не так много работаете параллельно и привыкли к ментальной модели веток и stash. Возможно, теперь вы будете использовать только worktrees. А может, захотите и то, и другое!</p><p>Мир у ваших ног, и попробовать всё это можно уже сегодня в приложении GitHub Copilot.</p><p><b>Об авторе.</b> Cassidy Williams — старший директор по адвокации разработчиков в GitHub. Она создаёт ПО, консультирует стартапы и учит разработчиков строить лучше. Подписаться на её еженедельную рассылку можно на <a href="https://cassidoo.co/newsletter">cassidoo.co/newsletter</a>.</p><h2>Выводы</h2><p>Git worktrees — способ работать с несколькими ветками одновременно, не прерывая текущую задачу и не рискуя запутаться в stash. Они особенно удобны при параллельной работе с ИИ-агентами и встроены в приложение GitHub Copilot по умолчанию. Попробуйте — возможно, именно они упростят ваш рабочий процесс.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как построить API-интеграцию оплаты для цифровых ключей и игровых сервисов</title>
      <link>https://tproger.ru/articles/kak-postroit-api-integraciyu-oplaty-dlya-cifrovyh-klyuchej-i-igrovy</link>
      <comments>https://tproger.ru/articles/kak-postroit-api-integraciyu-oplaty-dlya-cifrovyh-klyuchej-i-igrovy?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-postroit-api-integraciyu-oplaty-dlya-cifrovyh-klyuchej-i-igrovy</guid>
      <description><![CDATA[<p>Как построить API-интеграцию оплаты для цифровых ключей и игровых сервисов. Автоматизация платежей, пополнение Steam, выбор API-партнера и масштабирование магазина.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-postroit-api-integraciyu-oplaty-dlya-cifrovyh-klyuchej-i-igrovy">Как построить API-интеграцию оплаты для цифровых ключей и игровых сервисов</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Xbox]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Epic Games]]></category>
      <category><![CDATA[PlayStation]]></category>
      <category><![CDATA[Discord]]></category>
      <category><![CDATA[Steam]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 15 May 2026 04:43:34 GMT</pubDate>
      <content:encoded><![CDATA[<p>Рынок цифровых товаров за последние несколько лет вырос в полноценную инфраструктурную индустрию. Продажа игровых ключей, внутриигровой валюты, подписок и пополнений кошельков давно перестала быть «серой нишей» и превратилась в высококонкурентный сегмент e-commerce с миллионами транзакций ежедневно. Steam, PlayStation, Xbox, Nintendo, Epic Games, Discord Nitro, Game Pass — пользователи привыкли получать цифровой продукт мгновенно, без задержек и ручной обработки.</p><p>Для владельцев маркетплейсов, игровых магазинов и сервисов автоматизация оплаты сегодня становится не преимуществом, а обязательным условием масштабирования. Именно поэтому API-интеграции для цифровых платежей и автоматического пополнения игровых сервисов стали ключевым технологическим инструментом в индустрии.</p><h2>Почему ручная обработка больше не работает</h2><p>Большинство начинающих проектов стартуют одинаково: оператор вручную проверяет оплату, подтверждает заказ и отправляет ключ или проводит пополнение аккаунта. Пока заказов немного — схема кажется рабочей. Но после роста трафика начинаются проблемы:</p><ul><li>задержки обработки;</li><li>ошибки операторов;</li><li>потеря заказов;</li><li>возвраты из-за долгого подтверждения;</li><li>невозможность работать 24/7;</li><li>высокий риск мошенничества.</li></ul><p>В сегменте цифровых товаров пользователь ожидает моментальную выдачу. Если пополнение Steam занимает не секунды, а минуты — конверсия падает. Особенно в периоды распродаж, релизов крупных игр и сезонных акций.</p><p>Именно поэтому современные площадки переходят на автоматизированную архитектуру: платежный шлюз + API поставщика цифровых услуг + система мгновенной обработки заказов.</p><h2>Почему бизнес выбирает GGPay</h2><p>На фоне растущего рынка особое внимание получают сервисы, которые совмещают удобный API, стабильную инфраструктуру и понятную финансовую модель.</p><p>Одним из таких решений сегодня является<a href="https://ggpay.gg/steam?utm_id=928fe578" rel="follow"> GGPAY</a> — сервис для пополнения Steam и других цифровых платформ с поддержкой автоматизированной обработки платежей.</p><p>Платформа ориентирована как на конечных пользователей, так и на владельцев цифровых магазинов, маркетплейсов и игровых сервисов. Среди ключевых преимуществ:</p><ul><li>стабильная работа API;</li><li>автоматическое проведение платежей;</li><li>поддержка популярных способов оплаты;</li><li>низкие комиссии;</li><li>высокая скорость зачисления;</li><li>работа 24/7;</li><li>удобная интеграция для сайтов и Telegram-проектов.</li></ul><p>Для владельцев цифровых площадок особенно важно, что подобные сервисы позволяют быстро запускать автоматизированную продажу без необходимости строить собственную сложную платежную инфраструктуру с нуля.</p><h2>Как устроена API-интеграция цифровых платежей</h2><p>С технической точки зрения система выглядит достаточно просто, хотя внутри скрывается сложная логика маршрутизации и проверки транзакций.</p><p>Типовой процесс выглядит следующим образом:</p><ol><li>Пользователь выбирает цифровой товар или пополнение.</li><li>Сайт формирует заказ.</li><li>Платежный шлюз принимает оплату.</li><li>После подтверждения транзакции сервер обращается к API поставщика.</li><li>API выполняет пополнение или выдает цифровой ключ.</li><li>Клиент получает результат автоматически.</li></ol><p>Подобная модель давно используется в международной игровой индустрии и интегрируется через REST API, callback-уведомления и защищенные webhook-системы.</p><p>Главное преимущество такой схемы — отсутствие ручной обработки. Бизнес получает возможность масштабироваться практически без увеличения штата.</p><h2>Какие задачи решает API для цифровых товаров</h2><p>Современные API-платформы позволяют автоматизировать практически весь цикл продажи:</p><ul><li>пополнение Steam;</li><li>продажу игровых ключей;</li><li>выдачу gift card;</li><li>оплату подписок;</li><li>работу с региональными балансами;</li><li>массовую обработку заказов;</li><li>автоматический возврат;</li><li>мониторинг статусов транзакций;</li><li>защиту от дублирования платежей.</li></ul><p>Для крупных площадок особенно важна возможность работать с несколькими поставщиками одновременно. Это позволяет распределять нагрузку, снижать комиссии и поддерживать стабильность даже во время пикового спроса.</p><h2>На что обращать внимание при выборе API-партнера</h2><p>Ошибка многих проектов — выбор поставщика исключительно по размеру комиссии. На практике стабильность API намного важнее разницы в 1–2%.</p><p>При выборе сервиса необходимо оценивать:</p><h3>1. Скорость обработки</h3><p>Для игровых сервисов критична мгновенная выдача. Пользователь не готов ждать 10–15 минут после оплаты.</p><h3>2. Аптайм инфраструктуры</h3><p>Если API регулярно падает во время крупных распродаж Steam — бизнес теряет деньги и репутацию.</p><h3>3. Наличие webhook и callback-систем</h3><p>Это основа автоматизации статусов платежей.</p><h3>4. Документация</h3><p>Качественная документация сокращает время интеграции в разы.</p><h3>5. Поддержка популярных способов оплаты</h3><p>СБП, банковские карты, криптовалюты, электронные кошельки — современный рынок требует гибкости.</p><h3>6. Защита от мошенничества</h3><p>Антифрод-механизмы и валидация заказов особенно важны в сегменте цифровых товаров.</p><h2>Почему рынок активно переходит на автоматические пополнения Steam</h2><p>Steam остается крупнейшей игровой платформой мира, а пополнение кошелька — одним из самых востребованных цифровых продуктов в СНГ и Восточной Европе.</p><p>После изменений в международной платежной инфраструктуре спрос на альтернативные способы пополнения вырос кратно. На этом фоне появились специализированные сервисы, работающие через API-интеграции и автоматические платежные шлюзы.</p><p>Сегодня пользователи ожидают:</p><ul><li>низкую комиссию;</li><li>мгновенное зачисление;</li><li>стабильную работу;</li><li>поддержку разных регионов;</li><li>прозрачный курс конвертации;</li><li>отсутствие ручных подтверждений.</li></ul><p>Именно поэтому автоматизированные сервисы показывают значительно более высокую конверсию по сравнению с полуавтоматическими решениями.</p><h2>Как выглядит современная архитектура цифрового магазина</h2><p>Профессиональная инфраструктура обычно включает несколько уровней:</p><ul><li>frontend магазина;</li><li>платежный шлюз;</li><li>сервер обработки заказов;</li><li>API-поставщик цифровых товаров;</li><li>систему логирования;</li><li>антифрод-модуль;</li><li>резервные каналы оплаты.</li></ul><p>Дополнительно многие проекты подключают аналитические сервисы, отслеживающие:</p><ul><li>процент успешных транзакций;</li><li>скорость выдачи;</li><li>причины отказов;</li><li>нагрузку по регионам;</li><li>эффективность платежных методов.</li></ul><p>Такой подход позволяет масштабировать платформу практически без ограничений.</p><h2>Какие технологии будут доминировать дальше</h2><p>Рынок цифровых платежей продолжит двигаться в сторону полной автоматизации. Уже сейчас активно развиваются:</p><ul><li>direct top-up через Steam ID;</li><li>мультивалютные API;</li><li>криптовалютные расчеты;</li><li>AI-антифрод;</li><li>распределенные платежные системы;</li><li>автоматические системы маршрутизации транзакций.</li></ul><p>При этом требования пользователей становятся только жестче: скорость, надежность и прозрачность превращаются в стандарт индустрии.</p><h2>Заключение</h2><p>API-интеграция оплаты для цифровых ключей и игровых сервисов — это уже не дополнительная функция, а фундамент современного digital-бизнеса. Автоматизация позволяет масштабировать продажи, снижать издержки, минимизировать ошибки и обеспечивать мгновенную выдачу цифрового товара.</p><p>Именно поэтому проекты, работающие в сегменте игровых пополнений и цифровых товаров, всё чаще выбирают готовые инфраструктурные решения вместо ручной обработки заказов.</p><p>А сервисы вроде GGPAY становятся частью новой экосистемы цифровых платежей, где скорость обработки, стабильность API и удобство пользователя напрямую влияют на рост бизнеса и удержание аудитории.</p><p><i>Реклама. Рекламодатель: ОсОО «НОВАПЭЙ», ИНН:9909710276, erid: 2SDnjf2S7a2</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Как я перестал метаться между нейросетями и устроил им общий экзамен</title>
      <link>https://tproger.ru/articles/kak-ya-perestal-metatsya-mezhdu-nejrosetyami-i-ustroil-im-obshhij-ekz</link>
      <comments>https://tproger.ru/articles/kak-ya-perestal-metatsya-mezhdu-nejrosetyami-i-ustroil-im-obshhij-ekz?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[AIguide]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-ya-perestal-metatsya-mezhdu-nejrosetyami-i-ustroil-im-obshhij-ekz</guid>
      <description><![CDATA[<p>Я рассказываю, как перестал доверять рандомным «вау»-кадрам и устроил честный экзамен нейросетям для генерации изображений. Замерял качество, скорость, форматы и стоимость на реальных задачах, а в итоге собрал понятный пайплайн выбора AI-сервисов без магии и маркетинга.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-ya-perestal-metatsya-mezhdu-nejrosetyami-i-ustroil-im-obshhij-ekz">Как я перестал метаться между нейросетями и устроил им общий экзамен</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 12 May 2026 09:54:04 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Оглавление</h2><ol><li>Как я утонул в генерациях</li><li>Экзамен вместо «прыжков» по сервисам</li><li>Небольшой технический конвейер</li><li>Зачем цифры важнее впечатлений</li><li>Простой тест на форматы</li><li>Как ведут себя Riverflow, Flux и Seedream</li><li>Отчёты, артефакты и спокойная аналитика</li><li>Сценарий «восемь формулировок»</li><li>Зрелый подход к выбору AI</li></ol><p>В прошлой статье я рассказывал, как собрал тестовый стенд для AI‑генерации. Теперь — про то, как превратил его в живой процесс с разными сценариями и метриками.</p><h2>1. Как я утонул в генерациях</h2><p>Я осознал что  в очередной раз листал чат и не мог найти тот самый удачный вариант обложки.</p><p>Ситуация повторялась по одному и тому же шаблону. Запускаю один сервис — получаю результат, морщу лицо и сразу иду в другой. Там промпт приходится переформулировать: движок по-другому читает слова. В третьем генераторе наконец складывается приятная композиция, но детализация рушит весь смысл. Через пару дней на диске лежит россыпь PNG, а я уже не понимаю, где оказался осознанный успех, а где просто повезло. В какой-то момент я сказал себе: стоп. Случайные «попробую тут, попробую там» не ведут никуда.</p><h2>2. Экзамен вместо «прыжков» по сервисам</h2><p>Тогда я придумал простое правило. Любой сервис, который претендует на место в моём рабочем наборе, должен пройти экзамен. Не приятную беседу с общими вопросами, а одинаковый для всех, жёсткий сценарий. Без исключений и любимчиков.</p><h2>3. Небольшой технический конвейер</h2><p>Реализация получилась до обидного простой. Node.js, TypeScript, запуск через tsx. Список моделей вынесен в отдельный конфиг, API-ключ лежит в .env, а команды запуска выглядят вроде npm run test:niche или npm run test:collage-2x2-eight-prompts. Я взял творческий хаос и сложил его в аккуратный pipeline.</p><p>Дальше всё происходит автоматически: запускаешь тест — и один и тот же набор задач последовательно проходит через всех кандидатов. Мой вклад заканчивается на нажатии Enter.</p><h2>4. Зачем цифры важнее впечатлений</h2><p>Зачем вообще так усложнять? Потому что мантра «любая нейросеть — она и есть нейросеть» на практике не работает. Разброс колоссальный. Один сервис очень аккуратно держит геометрию кадра, но мелкие детали превращает в мыло. Другой рисует фактуру так, что хочется печатать и вешать, но при запросе «коллаж 3×3 с чёткими границами» внезапно решает творчески переосмыслить сетку. Третий стабильно отвечает и по времени, и по предсказуемости, но на сотне запросов выписывает такой чек, что хочется закрыть вкладку.</p><p>Если не фиксировать метрики, всё превращается в разрозненные ощущения. Сегодня это кажется идеальным инструментом, завтра тот же сервис тихо сжигает бюджет на десятке однотипных задач. И ты не можешь точно сказать, в какой момент всё поехало.</p><h2>5. Простой тест на форматы</h2><p>Возьмём самый базовый пример — проверка соотношения сторон. Формулировка элементарная: закат над горами, три варианта — 3:4, 1:1 и 16:9. Казалось бы, минимальный уровень адекватности. Но нет.</p><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/967623f7-34c5-4109-ae88-7c3ccd8122f0.webp" alt="" /><figcaption>таблица 1</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/c77d406d-862c-492c-bc89-733b8cb50349.webp" alt="" /><figcaption>таблица 2</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/2b48f70f-e37d-4ab1-bc2a-826a5fa72d56.webp" alt="" /><figcaption>таблица 3</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/1b27a8d8-19e1-4a94-968b-475fc8cea34c.webp" alt="" /><figcaption>таблица 4</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/ad59138a-e1f9-49f7-ae5c-03c3819768e9.webp" alt="" /><figcaption>таблица 5</figcaption></figure><p>Достаточно пробежать глазами столбец со статусом. Три запроса — три быстрых проверки «на глаз». Там, где на 3:4 и 16:9 горит FAIL, модель откровенно игнорирует задачу и рисует квадрат или удобный для себя формат. И это при том, что промпт простейший: не сложная сцена, не коллаж — всего лишь «закат, горы и нужная рамка».</p><h2>6. Как ведут себя Riverflow, Flux и Seedream</h2><p>Если посмотреть на результаты, riverflow-v2-pro аккуратно соблюдает все три формата. Но за эту аккуратность приходится платить временем: портретная картинка генерируется около 360 секунд. Шесть минут — роскошь, если у вас в руках горящий дедлайн. Упрощённая версия, riverflow-v2-fast, выдаёт правильные форматы за секунды и остаётся в адекватных рамках по времени — это уже инструмент для реальных задач.runware+2</p><p>С моделями Flux история другая. Почти вся линейка black-forest-labs стабильно промахивается по нестандартным форматам: колонка «Соотношение» упорно показывает 4/3 или 1/1, хотя в запросе чётко указано «16:9, wide landscape». Относительно ровно ведёт себя только flux.2-max, который хотя бы честно выдаёт квадрат, но проблемы с другими соотношениями никуда не деваются.github+1</p><p>Seedream-4.5 от Bytedance, напротив, поражает скоростью: ответы прилетают за 7–8 секунд, но модель регулярно игнорирует заданный формат и возвращает квадрат 2048×2048. Для макета, привязанного к конкретным пропорциям — сторис, постера или баннера — такая «быстрота» только ломает всю вёрстку.eachlabs+1</p><h2>7. Отчёты, артефакты и спокойная аналитика</h2><p>Вся эта конструкция нужна ради пары простых эффектов. Каждый запуск сохраняет статус, итоговый размер, время генерации и, где это важно, стоимость. После завершения прогона скрипты собирают HTML-отчёт. Открываешь его в браузере — и на одном экране сразу видно, кто действительно справился, а кто только шумит.</p><p>Особенно сильно это помогает в задачах, где критична композиция: нужна ровная сетка 2×2 или 3×3 без самодеятельности в духе «я тут чуть подвину, так красивее». Это как раз те случаи, когда от сервиса нужна дисциплина, а не внезапные художественные «инициативы».</p><h2>8. Сценарий «восемь формулировок»</h2><p>Отдельный пласт наблюдений даёт сценарий «восемь формулировок» (collage-2x2-eight-prompts). Суть задачи не меняется, контент остаётся одним и тем же. Я варьирую только подачу: где-то пишу запрос грубо и коротко, где-то — щадяще и структурно, местами добавляю лишний контекст.</p><p>На этом месте становится видно, как модель реагирует не на саму тему, а на стиль запроса. Одна и та же нейросеть спокойно выдерживает строгое техническое ТЗ и проваливается при формулировке «сделай красиво, сам понимаешь». После таких тестов по-другому относишься к промптам: начинаешь формулировать точнее, понимая, какая модель как «слушает» текст. И внезапно исчезают загадки в духе «почему здесь получилось, а там всё развалилось».</p><h2>9. Зрелый подход к выбору AI</h2><p>Главный вывод из всей этой истории довольно приземлённый. Выбирать AI-сервисы по рекламе, по восторженным постам в Telegram или по одному удачному демо-кадру — путь к разочарованию. Их нужно ставить в одинаковые условия. Прогонять по своим реальным задачам, а не по чужим презентациям. Сохранять результаты и сравнивать их по конкретным цифрам.</p><p>Когда делаешь так, выбор перестаёт быть эмоциональной пыткой в стиле «нравится / не нравится». Он превращается в спокойное рабочее решение: этот сервис — для быстрых черновиков, этот — для вылизанной композиции, этот — для длинных и сложных запросов, в которых ошибка по смыслу недопустима. В этот момент генерация перестаёт быть магическим ритуалом с сюрпризами и превращается в нормальный, предсказуемый инструмент. Таким, каким он и должен был быть изначально.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как я написал E2EE-мессенджер на Spring Boot и WebCrypto — и почему сервер не видит сообщения</title>
      <link>https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch</link>
      <comments>https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Василенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch</guid>
      <description><![CDATA[<p>Разбор архитектуры E2EE-мессенджера на Spring Boot 3, React и WebCrypto: X3DH, symmetric ratchet, AES-GCM, WebSocket, multi-device и ограничения реализации.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch">Как я написал E2EE-мессенджер на Spring Boot и WebCrypto — и почему сервер не видит сообщения</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Stack Overflow]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Алиса]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[5g]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 05 May 2026 05:35:02 GMT</pubDate>
      <content:encoded><![CDATA[<figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/240e412b-4307-49f9-b24f-bde7e0a7fd9a.webp" alt="" /></figure><p>Я Java-разработчик и в основном работаю с backend: Spring Boot, базы данных, интеграции, авторизация, WebSocket — всё то, что обычно находится за интерфейсом.</p><p>В какой-то момент я поймал себя на мысли: я каждый день пользуюсь мессенджерами, но плохо понимаю, как они устроены внутри. Окей, JWT, WebSocket, PostgreSQL, Redis — это понятно. Но что технически означает фраза "end-to-end encryption"? Как сервер доставляет сообщения, если он не должен их читать? Где живут ключи? Что хранится в базе? Что происходит, если у пользователя два устройства?</p><p>Решил разобраться через практику. Написал мессенджер с нуля. Назвал Chaos Messenger.</p><p>Сразу честно: криптографическую часть я изучал вместе с Claude и ChatGPT — читал спецификации X3DH и Double Ratchet, разбирал примеры, задавал вопросы, пока не сложилась цельная картина. Frontend тоже делался с активной помощью ChatGPT: я backend-разработчик, React для меня не основная среда. Но архитектура, backend, интеграция WebCrypto, модель конвертов, хранение сообщений и принципиальные решения — мои.</p><p>Для меня AI здесь был не заменой понимания, а инструментом — примерно как документация, Stack Overflow и ревью коллег. Без понимания threat model и архитектуры такой проект всё равно не собрать.</p><p>В статье расскажу, как работает E2EE изнутри: как устанавливается сессия через X3DH, как каждое сообщение получает отдельный ключ через Symmetric Ratchet, почему сервер хранит только зашифрованные конверты, и какие ошибки я допустил по дороге.</p><p>Стек: Spring Boot 3, React 18, WebCrypto API, PostgreSQL, Redis, WebSocket/STOMP, Prometheus, Grafana.</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/4b028f37-2de1-46ea-a247-567f74fb3081.webp" alt="" /></figure><h2>Важная оговорка про web-E2EE</h2><p>Когда я говорю, что сервер не может прочитать сообщения, я имею в виду backend, базу данных, WebSocket-слой и уже сохранённые ciphertext-конверты. У них нет ключей и plaintext.</p><p>Но у web-E2EE есть отдельная проблема: frontend-код тоже приходит с сервера. Теоретически скомпрометированный сервер может отдать изменённый JavaScript, который украдёт ключи или plaintext до шифрования. Это ограничение не конкретно моего проекта, а браузерной модели в целом.</p><p>Поэтому корректная формулировка такая: backend не получает ключи и не может расшифровать уже переданные или сохранённые сообщения. Защита от подмены клиентского кода — отдельный слой безопасности: подпись сборок, независимая верификация клиента, desktop/mobile-приложения, reproducible builds.</p><h2>Почему обычный подход не работает</h2><p>Большинство "мессенджеров" на GitHub выглядят примерно так:</p><p>Сервер знает всё. Видит каждое сообщение. Если БД утекла — утекла вся переписка. Если сервер взломали — читай что хочешь. Если завтра компания решит продать данные — технически ничего не мешает.</p><p>E2EE решает это радикально: backend не получает ключи и не хранит plaintext. Сообщение шифруется на устройстве отправителя до отправки в сеть, а расшифровывается только на устройстве получателя.</p><p>Это уже не вопрос политики конфиденциальности в стиле "мы обещаем не читать". Это архитектурное ограничение: если у сервера нет ключа, он не может превратить ciphertext обратно в текст.</p><p>Звучит как магия. На самом деле — два протокола и немного WebCrypto.</p><h2>Главная идея: конверты</h2><p>Представь что Алиса хочет написать Бобу. Вместо того чтобы положить письмо на стол и надеяться что никто не прочитает — она кладёт его в запечатанный конверт. Конверт может открыть только Боб своим ключом. Сервер просто передаёт конверт не заглядывая внутрь.</p><p>Именно так это работает в коде. В базе данных у меня это выглядит так:</p><p>Когда я впервые увидел</p><p>в своей БД вместо текста — стало понятно, что модель наконец работает правильно: сервер создал сообщение, доставил его, сохранил метаданные, но так и не узнал содержимое.</p><p>А вот что сервер возвращает при запросе списка чатов через API:</p><p>Не</p><p>. Не</p><p>. Буквально</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/b466ad91-20da-4e64-8b78-f6e08d2851d5.webp" alt="" /></figure><p>(DevTools → Network → ответ API с</p><p>)</p><h2>Откуда берутся ключи: X3DH</h2><p>Главный вопрос: как Алиса и Боб получают общий секрет, если они никогда раньше не общались? И как сделать это так, чтобы сервер только помог передать публичные данные, но сам не смог вычислить итоговый ключ?</p><p>Для этого используется X3DH — Extended Triple Diffie-Hellman, протокол из экосистемы Signal. Его задача — установить общий секрет между двумя устройствами, используя долгосрочные и временные ключи.</p><h2>Что хранится на сервере</h2><p>Когда пользователь регистрирует устройство, он загружает на сервер пакет публичных ключей:</p><p>На сервер уходят только публичные части. Приватные ключи сериализуются и хранятся локально в браузере — и никогда не покидают устройство в сеть.</p><p>Здесь важно сказать честно: хранение приватных ключей в</p><p>Более строгий вариант — использовать Web Crypto API с</p><p>, чтобы приватный ключ жил внутри браузерного crypto runtime и его нельзя было экспортировать в байты. Но у этого подхода есть практическая сложность: ключи нужно переживать между перезагрузками страницы, синхронизировать с IndexedDB, аккуратно восстанавливать состояние устройства и не сломать UX.</p><p>В браузерных E2EE-приложениях обычно приходится выбирать между несколькими вариантами:</p><ul><li>Сериализуемые ключи в localStorage или IndexedDB — проще реализовать, но нужно очень серьёзно относиться к XSS и целостности frontend-кода.</li><li>extractable: false + IndexedDB — безопаснее, но сложнее в реализации и восстановлении состояния.</li><li>Нативное secure storage вроде Android Keystore или iOS Secure Enclave — лучший вариант для мобильных клиентов, но он недоступен обычному web-приложению.</li></ul><p>В текущей версии Chaos Messenger используется первый вариант. Это осознанный компромисс для pet/open-source проекта и удобного запуска в браузере. Переход на non-extractable ключи и более строгую модель хранения стоит в roadmap.</p><p>Ключевой момент: backend всё равно не получает приватные ключи и не может расшифровать сохранённые ciphertext-конверты. Но защита ключей на клиенте — отдельная задача, и её нельзя честно замалчивать.</p><h2>Установка сессии</h2><p>Когда Алиса открывает переписку с Бобом впервые, происходит следующее:</p><p>В классическом X3DH четвёртая DH-операция с one-time prekey опциональна: она выполняется, если сервер выдал доступный OPK получателя. В моей реализации устройство публикует набор one-time prekeys при регистрации, поэтому первое сообщение обычно использует DH4. Если OPK закончились, сессию всё равно можно установить через остальные DH-компоненты, но это уже менее сильный вариант.</p><p>Боб, получив конверт с эфемерным публичным ключом Алисы, повторяет те же операции со своими приватными ключами и получает тот же самый</p><p>. Математика симметрична.</p><p>Сервер в этот момент видит только публичные ключи и зашифрованный конверт. Он помогает устройствам найти друг друга, но не участвует в вычислении секрета.</p><p>Получить</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/e7bbacf3-4fd2-4710-863a-2c710b1f6759.webp" alt="" /></figure><h2>Как шифруется каждое сообщение: Symmetric Ratchet</h2><p>X3DH даёт нам стартовый</p><p>. Но использовать один и тот же ключ для всех сообщений — плохая идея. Если использовать один ключ для всей переписки, компрометация этого ключа сразу открывает весь поток сообщений.</p><p>Решение — симметричный ratchet. После каждого сообщения цепочка ключей продвигается вперёд:</p><p>Визуально это выглядит так:</p><p>используется для шифрования одного сообщения через AES-GCM, после чего уничтожается. Если атакующий компрометирует</p><p>— он прочитает только второе сообщение.</p><p>В рамках такой симметричной цепочки это даёт forward secrecy назад по цепочке: зная текущий или отдельный</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/939a74f7-60c5-4816-85f0-05b5afdc9845.webp" alt="" /><figcaption>(диаграмма схемы chainKey → messageKey)</figcaption></figure><p>Само шифрование сообщения:</p><p>А вот что уходит на сервер — живой пример из DevTools:</p><p>Сервер получает</p><p>и</p><p>. Расшифровать без</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/b5e24cda-6fd9-4b15-9f27-3eb9b4f843b0.webp" alt="" /></figure><h2>Важная оговорка: это ещё не полный Double Ratchet</h2><p>В этом проекте реализован Symmetric Ratchet — цепочка, где из</p><p>для каждого сообщения выводится отдельный</p><p>Это защищает прошлые сообщения: если атакующий узнает текущий ключ или отдельный</p><p>, он не сможет откатить HMAC назад и получить старые ключи.</p><p>Но это не полный Double Ratchet из Signal Protocol.</p><p>В полном Double Ratchet есть ещё DH ratchet step: стороны периодически выполняют новый Diffie-Hellman обмен и обновляют root key. Это даёт break-in recovery — возможность восстановить безопасность будущих сообщений после компрометации части состояния.</p><p>В моей реализации DH ratchet step пока нет. Если атакующий получит актуальное состояние сессии на устройстве и сможет продолжать его читать, он сможет расшифровывать будущие сообщения до переустановки сессии. Это честное ограничение текущей версии, и оно стоит первым пунктом в roadmap.</p><h2>Мультиустройство: один пользователь, несколько конвертов</h2><p>Первый неочевидный момент: в E2EE сообщение адресуется не просто пользователю, а конкретным устройствам пользователя.</p><p>Если у Боба два устройства — телефон и ноутбук — нужен отдельный encrypted envelope для каждого устройства. Сервер не может взять один конверт, расшифровать его и "переупаковать" для второго устройства: у него нет ключей и он не знает plaintext.</p><p>Значит при отправке сообщения нужно зашифровать его отдельно для каждого устройства каждого участника чата.</p><p>Для чата где у каждого по 2 устройства — 4 конверта на одно сообщение. Для группы из 10 человек — потенциально 20 конвертов. Это нормально, это цена безопасности.</p><h2>Сервер: хранение и доставка конвертов</h2><p>На сервере сообщение создаётся с контентом</p><p>, а конверты сохраняются отдельно:</p><p>После сохранения — fanout по WebSocket. Каждое устройство получает свой конверт и только его:</p><p>Это важное отличие от обычного WebSocket-чата. В обычном чате сервер рассылает одно и то же событие всем участникам. В E2EE-чате сервер рассылает разные события разным устройствам: payload для каждого устройства содержит свой</p><p>Топик</p><p>— строго персональный. Устройство А не получает конверт устройства Б. Никакого broadcast — только адресная доставка.</p><h2>Архитектура целиком</h2><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/de0e3257-d893-459f-86ed-7ed8eace5d56.webp" alt="" /></figure><h2>Баг который долго не замечал</h2><p>В панели чатов показывается превью последнего сообщения. Я реализовал это через</p><p>Запускаю — в списке чатов у всех написано</p><p>.</p><p>Конечно. Сервер же не знает что там написано.</p><p>Я полчаса думал как решить это на сервере. Потом дошло: нельзя решить это на сервере — у него нет ключей. Решение только на клиенте.</p><p>После того как пользователь открыл чат и сообщения расшифровались — кешируем последнее в памяти:</p><p>Это хороший пример того, как E2EE меняет привычное мышление backend-разработчика. В обычном приложении preview — это поле в SQL-запросе. В E2EE-приложении preview — это локальное клиентское состояние, потому что только клиент видел plaintext.</p><p>Простое решение. Но чтобы к нему прийти нужно было полностью принять идею что сервер здесь просто не при делах — и перестать пытаться решить задачу на его стороне.</p><h2>Rate limiting: дыра которую легко не заметить</h2><p>Эндпоинт</p><p>отправляет SMS с кодом. Без защиты любой скрипт может дёргать его тысячи раз — это называется SMS pumping fraud, SMS стоят реальных денег.</p><p>Redis у нас уже был для хранения онлайн-статусов. Добавил rate limiting поверх него:</p><p>При превышении — HTTP 429 с заголовком</p><p>. Клиент знает через сколько секунд можно повторить.</p><p>Важный нюанс: в текущей реализации, если Redis недоступен, сервис не блокирует авторизацию полностью. Для pet-проекта это приемлемый компромисс: лучше рискнуть одним лишним SMS, чем положить вход в приложение.</p><p>В production я бы сделал строже: fallback in-memory лимит на инстанс, отдельные лимиты по IP и телефону, антифрод-логику и алерты на всплески отправки кодов.</p><h2>Авторизация WebSocket</h2><p>Отдельная история — авторизация WebSocket соединений. HTTP-эндпоинты защищены Spring Security автоматически, но WebSocket — другое дело. STOMP-соединение устанавливается один раз, и нужно проверять JWT при каждом подключении.</p><p>Отдельно важно не только проверить JWT, но и связать WebSocket-соединение с конкретным устройством. Пользователь может быть один, но устройств у него несколько, а encrypted envelope адресован именно</p><p>Поэтому при подключении я проверяю не только токен, но и</p><p>: устройство должно быть зарегистрировано и принадлежать текущему пользователю. Иначе легко случайно превратить per-device E2EE-доставку обратно в обычный broadcast по пользователю.</p><h2>Что получилось — живые скрины</h2><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/1fdfa006-f5c6-4731-a40f-50559be8832d.webp" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/c99164a5-021c-49ac-bcc4-3e38f9cd1c31.webp" alt="" /></figure><p>Что реализовано:</p><ul><li>E2EE-модель с per-device encrypted envelopes</li><li>X3DH session setup + Symmetric Ratchet + AES-GCM</li><li>Мультиустройство</li><li>Личные и групповые чаты</li><li>Realtime доставка через WebSocket/STOMP</li><li>Статусы SENT → DELIVERED → READ</li><li>Редактирование и soft delete сообщений</li><li>Online presence, typing indicator</li><li>Фото-вложения</li><li>Поиск пользователей</li><li>Rate limiting на SMS через Redis</li><li>Prometheus метрики + Grafana дашборд</li><li>Swagger UI с JWT авторизацией</li><li>24 backend-теста на Testcontainers, 12 frontend на Vitest, E2E на Playwright</li><li>GitHub Actions CI</li></ul><p>Что ещё не сделано:</p><ul><li>Полный Double Ratchet с DH ratchet step и break-in recovery</li><li>Ротация signed prekey и аккуратное пополнение one-time prekeys</li><li>Более строгая модель хранения приватных ключей на клиенте: non-extractable CryptoKey + IndexedDB</li><li>Защита от подмены frontend-кода: подпись сборок, независимая верификация клиента, reproducible builds</li><li>Android-клиент с Android Keystore</li><li>Реальный SMS-провайдер вместо кода в backend-логах</li><li>Push-уведомления без утечки содержимого сообщений</li><li>Более строгая metadata-модель для групповых чатов</li></ul><h2>Главный инсайт</h2><p>E2EE — это архитектурное решение, а не библиотека.</p><p>Нельзя взять обычный Spring Boot чат и просто "включить шифрование". Нужно с самого начала проектировать систему так, чтобы backend не был участником доверенной зоны: он не должен получать plaintext, не должен иметь ключи и не должен уметь пересобирать сообщение из данных в базе.</p><p>Это меняет почти всё:</p><ul><li>структуру БД — вместо текста появляются encrypted envelopes</li><li>API — сервер отдаёт [encrypted], а не preview сообщения</li><li>WebSocket — доставка идёт не по пользователю, а по конкретному устройству</li><li>мультиустройство — одно сообщение превращается в несколько ciphertext-конвертов</li><li>frontend — становится полноценной криптографической частью системы, а не просто UI</li></ul><p>Второй инсайт: мессенджер — это не "чат с WebSocket". В E2EE-модели это система доставки зашифрованных конвертов с адресацией по устройствам. Как только это принимаешь, многие странные на первый взгляд решения становятся логичными.</p><h2>Репозиторий</h2><p>Код открыт: <a href="https://github.com/vaazhen/chaos-messenger">github.com/vaazhen/chaos-messenger</a></p><p>В репозитории есть README на русском и английском, диаграммы, скриншоты, security audit, Docker Compose и запуск одной командой.</p><p>Проект не претендует на уровень production-криптомессенджера вроде Signal. Это учебный и инженерный open-source прототип, цель которого — показать, как E2EE меняет архитектуру backend, frontend и realtime-доставки.</p><p>Если вы делали что-то похожее — особенно интересно сравнить подходы к ротации prekey-ов, хранению non-extractable ключей в браузере и реализации DH ratchet step. Вопросы и критика приветствуются.</p>]]></content:encoded>
    </item>
    <item>
      <title>Адаптация открытого симулятора InferSim для оценки загрузки промышленных GPU</title>
      <link>https://tproger.ru/articles/adaptaciya-otkrytogo-simulyatora-infersim-dlya-ocenki-zagruzki-prom</link>
      <comments>https://tproger.ru/articles/adaptaciya-otkrytogo-simulyatora-infersim-dlya-ocenki-zagruzki-prom?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Дмитрий Ходыкин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/adaptaciya-otkrytogo-simulyatora-infersim-dlya-ocenki-zagruzki-prom</guid>
      <description><![CDATA[<p>Рассказываем, как доработали симулятор InferSim от Alibaba: добавили поддержку новых GPU (включая MetaX C500), расширили список моделей с гибридными архитектурами и сделали визуализацию на Streamlit. Инструмент позволяет оценивать задержки и требуемую память без запуска реального инференса и помогает избежать грубых ошибок при планировании закупок оборудования.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/adaptaciya-otkrytogo-simulyatora-infersim-dlya-ocenki-zagruzki-prom">Адаптация открытого симулятора InferSim для оценки загрузки промышленных GPU</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Визуализация]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[Hardware]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 04 May 2026 08:09:55 GMT</pubDate>
      <content:encoded><![CDATA[<p>Планирование аппаратных ресурсов под обслуживание больших языковых моделей — задача с высоким порогом ошибки. Потратишь лишнего — получишь неоправданные расходы. Сэкономишь — столкнёшься с деградацией пользовательского опыта. На российском рынке, где доступ к современным ускорителям ограничен, эта задача становится особенно острой.</p><p>Мы остановились на открытом симуляторе InferSim от Alibaba. Он умеет считать TTFT, TPOT и пропускную способность без запуска реального инференса. Но из коробки поддерживает только несколько топовых GPU и фиксированный набор моделей — для наших сценариев этого было недостаточно. Пришлось дорабатывать.</p><p><b>Как устроен InferSim</b></p><p>В основе симулятора — двухфазная схема. Сначала на целевом железе запускаются микро-бенчмарки: измеряется реальная производительность на типовых операциях внимания и матричных умножениях. Получается таблица коэффициентов Model FLOPs Utilization (MFU) — сколько процентов от теоретического максимума выдаёт конкретная карта на конкретной операции. Затем, уже без доступа к GPU, симулятор на основе этих MFU и аналитической модели вычисляет задержки. Именно такой подход даёт более точные предсказания, чем оценка по паспортной пропускной способности памяти.</p><p><b>Добавляем своё железо</b></p><p>Первым делом мы внесли в hardware/gpu.py поддержку MetaX C500 64GB. Характеристики добавляются через dataclass-экземпляры:</p><p>После этого c500 попадает в словарь gpu_map, и симулятор запускается с ключом --device-type C500 --world-size 2. Значения FLOPS и пропускной способности пришлось оценивать по косвенным источникам — производитель не публикует точных цифр. Позже планируем уточнить их через бенчмаркинг на реальном оборудовании. Таким же способом добавили Nvidia 1xH100 и A100.</p><p><b>Конфигурация моделей и одна болезненная ошибка</b></p><p>Симулятор ожидает стандартный config.json в формате Hugging Face. Для Qwen3-32B подготовили файл qwen3_32b_config.json:</p><p>Ключевой момент — правильное значение head_dim. У Qwen3-32B оно равно hidden_size / num_attention_heads = 5120 / 64 = 80. У нас ушло некоторое время, чтобы понять, почему симулятор выдаёт невалидные результаты: изначально в конфиге стояло значение 128. Пока не исправили — KV-кеш переоценивался, и метрики улетали в неадекватные цифры. После исправления всё встало на свои места.</p><p>Позже добавили поддержку Qwen3.5‑9B с её гибридной архитектурой, построенной на чередовании Gated DeltaNet и Gated Attention. Главная особенность модели в том, что около трёх четвертей слоёв не создают привычного KV‑кеша, а используют линейное внимание – компактное скрытое состояние, которое лишь обновляется с каждым новым токеном, не увеличиваясь в объёме. Это кардинально снижает расход памяти на длинных контекстах, но привносит и свою цену: на коротких дистанциях такая модель проигрывает в скорости Prefill, потому что Gated DeltaNet работает последовательно и хуже утилизирует матричные вычисления GPU.</p><p>Симулятор изначально не умел различать слои двух типов и считал весь KV‑кеш одинаково. Чтобы поддержать Qwen3.5, пришлось доработать расчёт задержек в классе HybridModel: теперь он отдельно обсчитывает full‑attention‑слои с полным кешем и linear‑attention‑слои без кеша, используя параметры num_full_attn_layers и num_linear_attn_layers из конфигурации. В директорию проекта models добавили hybrid_model.py, в котором сделали дополнительные расчёты:</p><p>Без такой дифференциации симулятор для Qwen3.5‑9B показывал E2E порядка 2 500 секунд вместо реальных нескольких секунд – та ошибка, которую мы долго отлавливали.</p><p><b>Визуализация и эксплуатация</b></p><figure><img src="https://media.tproger.ru/user-uploads/137657/2026-04-30/d68ad2ca-cbc0-4fe3-a4af-2f082a55ecdf.webp" alt="" /><figcaption>Пользовательский интерфейс на Streamlit</figcaption></figure><p>Чтобы не разбирать каждый раз текстовый вывод InferSim, сделали веб-интерфейс на Streamlit. Симулятор дёргается через subprocess, результаты парсятся из stdout и визуализируются:</p><ul><li>тепловые карты задержек (Prefill, Decode, E2E Total) для разных длин входных и выходных токенов;</li><li>анализ RPS с расчётом требуемой параллельности и сравнением с доступной памятью;</li><li>информация о занятой памяти в формате «X ГБ из Y ГБ».</li></ul><p>Кэширование через @st.cache_data позволило избежать повторных запусков симуляции при неизменных параметрах. Интерфейс получился достаточно удобным, чтобы даже коллеги без погружения в командную строку могли осмысленно сравнивать конфигурации.</p><p>Приложение упаковано в Docker и лежит в репозитории на <a href="https://github.com/DmitriyKhodykin/InferSim" rel="nofollow">GitHub</a>. Сервисы — сам Streamlit и Nginx в качестве обратного прокси с SSL-терминацией и базовой HTTP-аутентификацией. Деплой на VDS автоматизирован через GitHub Actions: собрали образ, отправили на сервер, перезапустили контейнеры. SSL-сертификаты Let's Encrypt обновляются по cron.</p><p><b>Что в итоге</b></p><p>Адаптированный InferSim не претендует на абсолютную точность — она ограничена качеством бенчмарков и коэффициентов MFU. Но инструмент позволяет избежать грубых ошибок при планировании, что в условиях ограниченного доступа к GPU и их высокой стоимости само по себе немало. Мы продолжаем калибровку симулятора и готовим обновлённые конфигурации для следующих моделей.</p><p>Репозиторий проекта открыт, будем рады замечаниям и предложениям от тех, кто решает схожие задачи.</p>]]></content:encoded>
    </item>
    <item>
      <title>Megamerges в Jujutsu: как работать с 5 ветками сразу через один octopus merge</title>
      <link>https://tproger.ru/translations/megamerges-v-jujutsu-kak-rabotat-s-5-vetkami-srazu-cherez-odin</link>
      <comments>https://tproger.ru/translations/megamerges-v-jujutsu-kak-rabotat-s-5-vetkami-srazu-cherez-odin?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/megamerges-v-jujutsu-kak-rabotat-s-5-vetkami-srazu-cherez-odin</guid>
      <description><![CDATA[<p>Перевод гайда Айзека Корбри: как собрать megamerge через octopus merge, какие алиасы упрощают jj stage, jj stack и jj restack, и чем это удобнее rebase.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/megamerges-v-jujutsu-kak-rabotat-s-5-vetkami-srazu-cherez-odin">Megamerges в Jujutsu: как работать с 5 ветками сразу через один octopus merge</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 21 Apr 2026 16:30:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы каждый день переключаетесь между 3–5 ветками в Git — фичи, багфиксы, PR на ревью, чужие ветки, от которых зависит ваш код — и каждое переключение ломает темп разработки, у <a href="https://tproger.ru/news/jj-cli-poverh-git-bez-staging-i-s-otkatom-lyuboj-operacii" rel="noopener">Jujutsu</a> есть рабочий процесс, который убирает эту боль. Он называется <i>megamerge</i>. Айзек Корбри описывает его так: один большой <i>octopus merge</i> (merge-коммит с тремя и более родителями), в который вы включаете все рабочие ветки сразу. Вы всегда работаете поверх суммы всех ваших изменений.</p><p><a href="https://jj-vcs.github.io/jj/" rel="noopener">Jujutsu</a> (сокращённо jj) — система контроля версий, совместимая с Git по протоколу, но с другой моделью коммитов: конфликты — сущность первого класса, commit и rebase — базовые операции, immutable и mutable коммиты отделены. В посте — перевод статьи Корбри с HN (249 points): зачем нужны megamerges, как их собирать и как поддерживать в актуальном состоянии через алиасы jj.</p><p><i>Пост написан для пользователей Jujutsu среднего уровня и для гитовых пользователей, которым любопытен jj. Специальные команды приведены в оригинальном виде (их не локализуют), пояснения — в комментариях к коду. Ключевые термины jj: <b>revset</b> — язык запросов к графу коммитов (аналог Git-revisions, но расширенный); <b>bookmark</b> — аналог ветки в Git, но не двигается автоматически за рабочей копией; <b>WIP</b> — work in progress, незавершённые изменения.</i></p><ul><li>Megamerge — octopus merge (коммит с тремя и более родителями), куда вы включаете все рабочие ветки: фичи, багфиксы, PR, чужие ветки-зависимости, локальные инструменты. Вы работаете поверх него.</li><li>Выгода: всегда видите сумму всех изменений разом; почти не ловите сюрприз-конфликты на пуше; быстро переключаетесь между задачами (просто редактируете код); можно легко делать drive-by-фиксы.</li><li>Собрать просто: jj new x y z + jj commit -m megamerge. Megamerge в remote не пушится — пушатся только ветки, из которых он собран.</li><li>Сабмит WIP-изменений: jj absorb (автоматически разбрасывает строки по «родным» коммитам) и jj squash --to X --interactive (вручную выбирать куски).</li><li>Поддержка актуальности — алиас restack: ребейзит только ваши mutable-коммиты на trunk, оставляя в покое чужие ветки.</li></ul><h2>Merge-коммиты в jj: обычный коммит с несколькими родителями</h2><p>Если вы обычный гит-пользователь (или пользователь Jujutsu, который ещё не дошёл до продвинутых процессов), возможно, вы удивитесь: в merge-коммите нет ничего особенного. Это не специальный случай с отдельными правилами — это обычный коммит, у которого несколько родителей. Он даже не обязан быть пустым.</p><p><i>Легенда вывода jj log: @ — текущая рабочая копия; ○ — mutable-коммит; ◆ — immutable-коммит (обычно trunk); ├─╮ — граф связей.</i></p><p>Удивит и второе: merge-коммиты не ограничены двумя родителями. Мерджи с тремя и более родителями в сообществе неофициально называют <i>octopus merge</i>. И если вы думаете: «в каком мире мне может понадобиться слить больше двух веток?» — на практике эта идея очень мощная. Именно octopus merges дают весь megamerge-воркфлоу.</p><h2>Так что же такое megamerge</h2><p>Суть в том, что в megamerge-воркфлоу вы редко работаете прямо поверх тика одной ветки. Вместо этого вы создаёте octopus merge (его и называем <i>megamerge</i>) как дочерний коммит от каждой рабочей ветки, которая вам важна. Это могут быть багфиксы, фича-ветки, ветки, ждущие PR, чужие ветки, от которых зависит ваш код, локальные окружения и даже приватные коммиты, которые не принадлежат ни к одной ветке. Всё, что вам важно, входит в megamerge. Главное помнить: <b>megamerge не пушится в remote — пушатся только ветки, из которых он собран</b>.</p><p>Если звучит как много — нормально. Вы же знаете, сколько сил уходит на смену контекста при возврате к старому PR. Но такой подход даёт несколько реально ценных вещей:</p><ul><li><b>Вы всегда работаете поверх суммы всех своих изменений.</b> Если ваша рабочая копия собирается и запускается — вся ваша работа гарантированно согласуется друг с другом.</li><li><b>Почти не встречаются сюрприз-конфликты.</b> В Jujutsu конфликты и так first-class (их не нужно «решать прямо сейчас»), а в megamerge-воркфлоу вы постоянно сливаете свои изменения — поэтому на стороне удалённого хостинга (GitHub/GitLab) конфликтов не возникает. Иногда проблемы случаются с изменениями контрибьюторов, но на практике это редкость.</li><li><b>Намного меньше трения при переключении задач.</b> Поскольку вы всегда работаете поверх megamerge, не нужно ходить в VCS — можно просто пойти править нужный код. Легко делать маленькие PR для попутных рефакторов и фиксов.</li><li><b>Проще держать ветки актуальными.</b> Небольшой алиас — и весь megamerge обновляется относительно trunk одной командой rebase. Разберём ниже.</li></ul><h2>Как собрать megamerge</h2><p>Старт — простой: новый коммит с каждой нужной веткой в качестве родителя. Автор любит давать этому коммиту имя и оставлять пустым:</p><p>Получаете пустой коммит поверх всего. Вот тут и идёт работа. Всё, что выше megamerge, считается WIP. Можно сплитить, создавать несколько веток из megamerge — всё, что хотите. Всё, что вы напишете, будет опираться на сумму содержимого megamerge — как и задумывалось.</p><p>В какой-то момент вы будете довольны результатом — и встанет вопрос:</p><h2>Как затем сабмитить изменения</h2><p>Как дотащить изменения до megamerge — зависит от того, куда они должны попасть. Основной инструмент — команда absorb: она сама определяет, в какой mutable-коммит ниже по дереву должен пойти каждый хунк или каждая строка, и автоматически разбрасывает их по нужным коммитам. «Каждый раз выглядит как фокус — логика absorb прозрачна: команда смотрит, в каком коммите ниже по дереву впервые появилась каждая изменяемая строка, и отправляет её туда». Это одна из ключевых фич Jujutsu, благодаря которой megamerge-воркфлоу работает плавно.</p><p>Но Jujutsu — красивый кусок софта, и у него есть автоматика. Команда absorb сделает бо́льшую часть работы за вас: определит, в какой mutable-коммит ниже по дереву должен пойти каждый ваш хунк или каждая строка, и автоматически их туда сквошит. «Каждый раз ощущается как магия — и не та чёрная магия, в которой ничего не разобрать, а хорошая, понятная». Это одна из ключевых фич Jujutsu, благодаря которой megamerge-воркфлоу вообще работает плавно.</p><p>Absorb не всегда ловит всё, но обычно укладывает около 90% изменений. Остальное — либо ручной squash --to (отправляет изменения в конкретный коммит), либо squash --to X --interactive (для выборочного переноса кусков). Если WIP-коммит содержит изменения для нескольких целей — сначала сплит командой split, либо тот же --interactive.</p><p>Если изменения должны попасть в новый коммит — не сильно сложнее. Если коммит относится к одной из ваших веток, просто ребейзим и двигаем bookmark:</p><p>Разложим этот rebase, чтобы было понятнее:</p><p>А если вы начали работу над совершенно новой фичей или наткнулись на баг — ещё проще. С парой алиасов можно легко добавить новый материал в megamerge:</p><p>Короткое пояснение, что делает closest_merge(to):</p><p>С этим revset-алиасом stack берёт произвольный revset и вставляет его между trunk() (основной веткой разработки) и megamerge:</p><p>Это полезнее, если несколько стеков изменений хочется включить параллельно. А если стек один, есть ещё один алиас, который подхватывает весь стек после megamerge:</p><p>Этот алиас не требует аргументов. Достаточно накоммитить и ввести stage:</p><p>Последний кусок пазла — неприятная реальность: есть ещё <i>другие люди</i>.</p><h2>Как держать всё это в актуальном состоянии</h2><p>Хороший вопрос — автор потратил пару месяцев, чтобы ответить на него в общем виде. У Jujutsu есть простой способ ребейзить всю рабочую ветку на основную ветку:</p><p>Но это работает, только если всё ваше рабочее дерево (worktree) состоит только из ваших изменений. Когда в графе есть коммиты, которые вам не принадлежат (untracked bookmark или чужие ветки), Jujutsu остановится, чтобы защитить их от перезаписи.</p><p>Решение — ребейзить только те коммиты, которыми вы реально управляете. Спасибо <a href="https://github.com/stephen-jennings" rel="noopener">Стивену Дженнингсу</a> за отличный revset:</p><p>Вместо того чтобы пытаться ребейзить всё дерево (как делает jj rebase --onto trunk()), этот алиас трогает только коммиты, которые можно двигать. Чужие ветки и работа поверх них остаются на месте. Флаг --simplify-parents заодно убирает лишние рёбра, которые могут остаться после ребейза. У автора эта команда не ломалась ни разу — даже на мегамерджах с девятью родителями разных контрибьюторов.</p><h2>TL;DR: рабочая конфигурация</h2><p>Megamerges в Jujutsu — рабочий способ уложить несколько параллельных задач в одно рабочее дерево. Для полноценной эргономики добавьте в конфиг через jj config edit --user:</p><p>Краткая шпаргалка по командам:</p><p>Ещё раз: megamerge не задуман для пуша в remote — это удобный способ увидеть всю картину целиком. Ветки всё равно публикуются отдельно, как обычно.</p><p>Megamerges подходят не всем — автор рассказывает, что получал испуганные взгляды, показывая своё рабочее дерево. Но, попробовав их один раз, вы с большой вероятностью обнаружите, что переключаетесь между задачами почти без усилий.</p><h2>Дополнительно: замечания автора</h2><ul><li>Флаг --simplify-parents в restack важен — он вычищает избыточные рёбра (если есть A→B→C и A→C, simplify-parents удалит A→C).</li><li>stage использует closest_merge(@)+::, а не closest_merge(@).. — оператор x.. эквивалентен ~::x и включает всё, что не является предком x. Это может затянуть лишнее.</li><li>В Git merge-коммиты, куда вносят изменения поверх разрешения конфликтов, называют <i>evil merge</i>. В Jujutsu такие мерджи уже не «злые» — модель Jujutsu устроена более консистентно.</li><li><b>Алиасы Jujutsu.</b> Есть несколько типов: <i>revset-алиасы</i> (кастомные функции, которые возвращают коммиты через <a href="https://jj-vcs.github.io/jj/latest/revsets/" rel="noopener">revset language</a>); <i>command-алиасы</i> (расширяют стандартные команды); <i>template-алиасы</i> (меняют формат вывода jj в терминале через templating language); <i>fileset-алиасы</i> (работают с файлами через fileset language).</li><li>Концепция <i>mutable/immutable</i>. Mutable-коммиты — те, что можно менять на регулярной основе. Это в основном lint (есть флаг --ignore-immutable), но он помогает не влипнуть. Алиасы mutable() и immutable() выбирают соответствующие коммиты.</li></ul><h2>FAQ</h2><h2>Выводы</h2><p>Megamerge-воркфлоу убирает одну конкретную боль: необходимость помнить, какие ветки с чем конфликтуют, и постоянно переключать контекст. Базовая схема: octopus merge как «рабочая площадка», absorb и squash для отправки изменений в нужные коммиты, restack для поддержания актуальности. Ничего магического — обычные коммиты и revsets, собранные в удобный процесс. Кто работает в воркфлоу <a href="https://tproger.ru/articles/git-flow-github-flow-i-trunk-based-development-kakoj-workflow" rel="noopener">Trunk-Based Development</a>, увидит знакомые паттерны — megamerge хорошо с ними сочетается.</p><p>Оригинал статьи: <a href="https://isaaccorbrey.com/notes/jujutsu-megamerges-for-fun-and-profit" rel="noopener">isaaccorbrey.com/notes/jujutsu-megamerges-for-fun-and-profit</a>. Обсуждение на Hacker News: <a href="https://news.ycombinator.com/item?id=47841129" rel="noopener">news.ycombinator.com/item?id=47841129</a>. Официальная документация Jujutsu: <a href="https://jj-vcs.github.io/jj/latest/" rel="noopener">jj-vcs.github.io/jj</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub запустил нативные Stacked PRs — альтернатива Graphite</title>
      <link>https://tproger.ru/news/github-vypustil-nativnye-stacked-prs-konec-graphite-i-spr</link>
      <comments>https://tproger.ru/news/github-vypustil-nativnye-stacked-prs-konec-graphite-i-spr?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-vypustil-nativnye-stacked-prs-konec-graphite-i-spr</guid>
      <description><![CDATA[<p>GitHub в Private Preview добавил нативные stacked PRs: разбивайте большую диффу на цепочку и мерджите одним кликом. CLI gh stack, Skills для ИИ-агентов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-vypustil-nativnye-stacked-prs-konec-graphite-i-spr">GitHub запустил нативные Stacked PRs — альтернатива Graphite</a>»</p>]]></description>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 16 Apr 2026 10:30:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если ваши пулл-реквесты разрастаются до 2000 строк и ревьюеры тонут в диффе — у GitHub теперь появился родной способ разбить большую задачу на стэк маленьких PR. <a href="https://github.github.com/gh-stack/">Stacked PRs</a> пока в Private Preview: чтобы получить UI со стек-картой и cascading rebase, нужно записаться в waitlist. Но открытый <a href="https://github.com/github/gh-stack">CLI-клиент gh stack</a> уже можно ставить — авторы пишут, что в нынешнем виде он работает против репозитория только если для вас включили preview.</p><p>Раньше стэки делали сторонними инструментами: облачный сервис <a href="https://graphite.dev">Graphite</a>, консольные клиенты <a href="https://github.com/ezyang/ghstack">ghstack</a> (от Meta) или <a href="https://github.com/getcord/spr">spr</a>. Все они симулировали стэки поверх обычного GitHub и ломались на ребейзах, merge queue и branch protection. Нативная реализация решает именно эти проблемы — о том, что с ней не так на старте и кому есть смысл пробовать прямо сейчас, разбираемся ниже.</p><ul><li><b>Статус:</b> Private Preview, нужен waitlist для репозитория</li><li><b>Что внутри платформы:</b> stack map в UI, cascading rebase, корректная работа branch protection и merge queue</li><li><b>CLI:</b> расширение gh stack открыто в гитхабе, алиас gs — команды init, add, push, submit</li><li><b>ИИ-агенты:</b> npx skills add github/gh-stack учит Claude Code и Codex разбивать задачи на слои</li><li><b>Кому идти сразу:</b> командам с регулярными PR 1500+ строк или большими диффами от ИИ-ассистентов</li><li><b>Кому подождать:</b> тем, кто уже на Graphite или делает в основном PR на 200 строк</li></ul><h2>Что такое stacked PRs</h2><p>Stacked PR (стек пулл-реквестов) — это цепочка PR, где каждый таргетит не main, а ветку PR ниже. Вместо одного огромного пулл-реквеста с пятью разными по смыслу изменениями вы делаете пять маленьких PR, которые читаются независимо и строятся один на другом.</p><p>Пример. Вы делаете фичу, которая требует нового API, роутов и фронтенда. Обычно это превращается в PR на 2000 строк, где ревьюер сначала вникает в API, потом забывает про него, когда смотрит роуты, путается в фронтенде и в итоге пишет «LGTM, не читал». Со стэком:</p><ul><li><b>PR #1</b> — auth-layer: новый API-слой (200 строк, одна тема)</li><li><b>PR #2</b> — api-routes: роуты на базе auth-layer, таргетит ветку PR #1</li><li><b>PR #3</b> — frontend: UI на базе роутов, таргетит ветку PR #2</li></ul><p>Ревьюеры читают по одному PR, дают фидбек по конкретной теме, и вы мержите всё разом, когда каждый слой одобрен. Подход называется «small PR culture» — мы <a href="https://tproger.ru/news/perestante-otpravljat-na-revju-1500-strok-kak-stekat-prs-chtoby-ne-utopljat-revjuerov">уже разбирали, почему команды переосмысляют формат пулл-реквестов</a>.</p><h2>Что GitHub сделал на уровне платформы</h2><p>Сторонние тулы уже давно давали стек на Git-уровне, но работали поверх обычного GitHub и ломались на ребейзах, merge queue и branch protection. Нативная поддержка закрывает эти углы:</p><ul><li><b>Stack map в UI</b> — навигация между PR прямо в интерфейсе, видно статус каждого слоя сразу</li><li><b>Cascading rebase</b> — ребейзнули PR внизу стэка, один клик — и все PR выше автоматически ребейзятся</li><li><b>Branch protection</b> — правила (ревью-апрув, passing checks) применяются против финальной целевой ветки (обычно main), а не против промежуточной</li><li><b>CI</b> — прогоняется для каждого PR в стэке так, будто он уже таргетит финальную ветку (не промежуточную)</li><li><b>Merge queue</b> — очередь GitHub, которая последовательно ребейзит и мерджит PR. Теперь понимает стэки: можно ставить в очередь как весь стэк, так и его часть</li><li><b>Частичный мердж стэка</b> — если одобрены только нижние два PR, можно слить их, а верхние оставить на доработку</li><li><b>API</b> — управление стэками через GraphQL и REST, интеграция с вашими CI-тулами</li></ul><h2>CLI gh stack: что внутри</h2><p>CLI — опциональное расширение к стандартному gh. Сокращает рутину: не надо вручную создавать ветки, проставлять base, делать серию rebase. Базовые команды следуют <a href="https://tproger.ru/news/vsem-rebjatam-primer-pochemu-pora-perestat-ispolzovat-git-flow">той же логике, что и современные workflow поверх Git</a> — работать мелкими слоями и синхронизироваться автоматически.</p><p>Базовый сценарий от GitHub:</p><p>Дальше — работа как с обычными PR, только с визуальной картой стэка. Хотите ребейзнуть auth-layer на свежий main — gs rebase, и вышележащие слои автоматически подтягивают новую базу.</p><h2>Интеграция с ИИ-агентами</h2><p>GitHub явно заточил stacked PRs под сценарий совместной работы с ИИ-агентами. Skills — это документированный формат инструкций для кодовых ассистентов: одна папка с markdown-файлами и примерами, которую агент читает и использует как расширение своего поведения. Команда npx skills add github/gh-stack добавляет такой скилл для <a href="https://github.com/anthropics/claude-code">Claude Code</a>, <a href="https://github.com/openai/codex">OpenAI Codex</a> и других агентов, которые поддерживают формат.</p><p>Скилл учит агента двум вещам: брать большую задачу и заранее разбивать её на слои (вместо того чтобы генерировать один огромный коммит), и работать поверх существующего стэка — добавлять новые слои или чинить нижние. Это решает одну из главных проблем ИИ-разработки: агент делает «всё сразу», ревью превращается в кошмар, а откатить часть изменений невозможно. Похожая мотивация была <a href="https://tproger.ru/news/github-copilot-teper-rabotaet-kak-agent-delaet-pr-bez-vas">у Copilot-агента, который собирает PR сам</a>, но без стэков он быстро упирается в размер диффа.</p><h2>Как попасть в Private Preview</h2><ol><li>Зайти на <a href="https://github.github.com/gh-stack/">github.github.com/gh-stack</a> и записаться в waitlist (кнопка «Sign up for the waitlist»)</li><li>Дождаться, пока GitHub включит фичу для вашей организации или репозитория — точных сроков они не называют</li><li>Включить в настройках репо: появится новая секция Stacked PRs в Settings → Pull Requests</li><li>Поставить расширение CLI: gh extension install github/gh-stack</li></ol><p>CLI-расширение распространяется свободно — его можно поставить уже сейчас из <a href="https://github.com/github/gh-stack">открытого репозитория github/gh-stack</a>. Но README расширения предупреждает: без включённого Private Preview на стороне сервера команды gs push и gs submit упрутся в API, который отвечает 404 или ошибкой доступа. Поставить CLI и посмотреть gh stack --help можно, реально прогонять стэки — только после активации preview в репозитории.</p><h2>Зачем это, если есть Graphite, ghstack и spr</h2><p>Существующие решения делятся на две группы. Graphite — коммерческий сервис: у него свой веб-интерфейс, бэкенд и платные тарифы, он синхронизирует стэк через GitHub API. Ghstack (Meta) и spr (Cord) — консольные клиенты: держат локальный граф стэка и пушат PR напрямую. Общее у них одно — стэк живёт где-то вне GitHub, а синхронизируется с ним через API.</p><p>Из-за этого все они ломаются в одном классе сценариев: когда кто-то из команды мержит через веб-интерфейс, делает force-push из терминала или запускает merge queue, локальный граф CLI или состояние сервиса Graphite разъезжаются с реальностью — и стэк приходится чинить руками.</p><p>Нативная реализация снимает этот класс проблем: стэк живёт на стороне сервера GitHub, UI и CLI синхронизируются с ним автоматически. Branch protection, merge queue, CI — всё работает без костылей. Для базового сценария «разбить большую диффу на стэк и слить её» стороннее звено становится необязательным.</p><p>У сторонних тулов остаётся ниша: автогенерация описаний PR через ИИ у Graphite, интеграция с Jira и Linear, аналитика по времени ревью — всё это GitHub не закрывает. Если вы уже платите Graphite за эту часть — ничего не сломается, тулы совместимы со Stacked PRs на уровне API.</p><p>Для российских разработчиков: GitHub работает с ограничениями для аккаунтов, подключённых из РФ с 2022 года — возможны блокировки при создании организаций и проблемы с оплатой приватных репозиториев. Нативные Stacked PRs становятся особенно полезны, если переходить на <a href="https://gitflic.ru">GitFlic</a>, <a href="https://gitverse.ru">GitVerse</a> или self-hosted GitLab, где аналогов стэков на платформенном уровне пока нет — но CLI-клиенты ghstack и spr работают и на них.</p><h2>Что делать прямо сейчас</h2><p>Если ваша команда регулярно сталкивается с ревью на 1500+ строк, PR, которые висят неделями, или большими диффами от ИИ-ассистентов — <a href="https://github.github.com/gh-stack/">встаньте в waitlist</a>, поставьте CLI gh extension install github/gh-stack и подготовьтесь к следующей крупной задаче. Пока ждёте активации — попробуйте разбить текущую большую задачу руками через последовательные PR с правильными base-ветками: это работает и в обычном GitHub, а CLI потом сделает то же самое автоматически.</p><p>Если вы уже на Graphite и довольны — переезд имеет смысл после выхода фичи из Private Preview и появления миграционного сценария. Небольшим командам с PR на 200 строк фича пока не нужна: инвестиции в стэки окупаются там, где большие задачи — частая история.</p><p>Нативная поддержка закрывает больную для крупных команд зону: большие изменения теперь можно разбивать без костылей, а ревью — делать по смыслу, а не по количеству строк.</p><p><b>Источники:</b> <a href="https://github.github.com/gh-stack/">официальный анонс GitHub Stacked PRs</a>, <a href="https://github.com/github/gh-stack">репозиторий CLI-расширения</a>, <a href="https://news.ycombinator.com/item?id=47757495">обсуждение на Hacker News</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>jj — CLI поверх Git без staging и с откатом любой операции</title>
      <link>https://tproger.ru/translations/jj-cli-poverh-git-bez-staging-i-s-otkatom-lyuboj-operacii</link>
      <comments>https://tproger.ru/translations/jj-cli-poverh-git-bez-staging-i-s-otkatom-lyuboj-operacii?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/jj-cli-poverh-git-bez-staging-i-s-otkatom-lyuboj-operacii</guid>
      <description><![CDATA[<p>Стив Клабник про jj (Jujutsu): рабочая копия = коммит, конфликты живут в истории, любой rebase откатывается одной командой. Разбираем концепции.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/jj-cli-poverh-git-bez-staging-i-s-otkatom-lyuboj-operacii">jj — CLI поверх Git без staging и с откатом любой операции</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 15 Apr 2026 15:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вас бесит git reset --hard, staging area и rebase-конфликты, которые приходится решать трижды — посмотрите на <b>jj</b> (CLI для <a href="https://github.com/jj-vcs/jj">Jujutsu</a>). Он работает поверх вашего Git-репозитория, не требует миграции и предлагает другую модель: рабочая копия — это коммит, у конфликтов нет маркеров в файлах, а любую операцию можно отменить одной командой.</p><p>Это адаптированный перевод <a href="https://steveklabnik.github.io/jujutsu-tutorial/">учебника Стива Клабника</a> (автор «The Rust Programming Language») про jj — с объяснением ключевых концепций и тем, чем они отличаются от Git. Автор сам пришёл к jj, попробовав его после <a href="https://v5.chriskrycho.com/essays/jj-init/">статьи Криса Крайко</a>, и признаётся: это редкий случай, когда инструмент одновременно проще и мощнее старого.</p><p><b>Git-совместимый бэкенд.</b> jj использует Git-репозиторий как хранилище, работает с вашими .git/ и удалёнными репо. Коллегам ничего менять не надо.</p><p><b>Рабочая копия — это коммит.</b> Нет отдельного staging area. Любое изменение файла сразу формирует новую версию коммита с тем же change ID.</p><p><b>Change ID ≠ commit ID.</b> Change — это «идея изменения», commit — её конкретное воплощение. Описание и содержимое можно менять, change ID остаётся стабильной ссылкой.</p><p><b>Anonymous branches.</b> Ветки не обязаны иметь имена: граф коммитов сам по себе задаёт структуру. Имена нужны только для push на GitHub.</p><p><b>First-class conflicts.</b> Конфликты хранятся в истории как часть коммита, а не как маркеры в файле. Rebase не останавливается на конфликте — продолжается, и потомки автоматически перестраиваются, когда вы фиксите исходник.</p><p><b>Operation log и jj undo.</b> Любая операция — в том числе rebase и abandon — откатывается одной командой. Потерять работу в jj сложнее, чем в Git.</p><h2>Установка и первый репозиторий</h2><p>jj написан на Rust. Самый простой способ — через cargo. На апрель 2026 актуальная версия — 0.40.x; учебник Клабника написан по 0.23.0, поэтому ниже в примерах показана именно она, чтобы совпадал вывод команд.</p><p>Альтернативы — Homebrew, пакеты для Linux, бинарники с <a href="https://jj-vcs.github.io/jj/latest/install-and-setup/">страницы установки</a>. После установки надо указать имя и почту:</p><p>Инициализация нового репозитория выглядит так:</p><p>Обратите внимание на jj git init, а не просто jj init. У jj есть собственный формат репозитория, но он пока экспериментальный. На практике все используют Git-бэкенд: изнутри это обычный .git/, который без проблем читает git log, IDE и CI-скрипты.</p><h2>Рабочая копия — это коммит</h2><p>Первое, что сбивает с толку git-пользователя: в jj нет «рабочей копии» и «индекса» как отдельных сущностей. Любое изменение файла сразу становится частью текущего коммита (помечается символом @).</p><p>Посмотрим статус свежего репо:</p><p>Даже пустой репозиторий уже содержит коммит yyrsmnoo. У него два идентификатора:</p><ul><li><b>Change ID</b> (yyrsmnoo) — стабильный идентификатор «идеи изменения». Это не hex, а короткая случайная строка из букв — jj специально выбирает алфавит так, чтобы ID читались и набирались проще, чем git-хеши.</li><li><b>Commit ID</b> (e7cfc43b) — конкретная реализация: набор файлов + описание.</li></ul><p>Это центральная концепция. Когда вы редактируете файл или меняете описание — commit ID обновляется, а change ID остаётся прежним. Change ID — это как будто номер задачи в трекере: ссылка на идею, не на конкретный снимок.</p><h2>Основной цикл: describe → work → new</h2><p>В Git вы сначала пишете код, потом коммитите с сообщением. В jj — наоборот: сначала описываете, что собираетесь сделать, потом работаете.</p><p>Без флага -m откроется редактор. Описание можно менять в любой момент и сколько угодно раз — change ID не поменяется, но commit ID обновится. Это удобно: пишете начальное описание, уточняете по мере работы.</p><p>Когда изменение готово, создаём следующее поверх него:</p><p>Всё. Коммит сформирован, можно продолжать работать в новой пустой рабочей копии. <b>Никаких git add, git commit и git status перед коммитом не нужно.</b> jj сам отслеживает, какие файлы поменялись.</p><blockquote>Иногда в jj всё ощущается так же, как в git, но наоборот. В git мы завершаем работу коммитом. В jj мы начинаем работу, создавая change, а потом правим код. Гораздо полезнее сначала написать, что ты собираешься сделать, и уточнять по ходу, чем придумывать commit message постфактум.</blockquote><h2>Squash vs Edit: два рабочих процесса</h2><p>У jj-сообщества сложились два устойчивых паттерна. Squash — любимый у Мартина, создателя jj. Edit — у тех, кому squash не зашёл.</p><h3>Squash workflow</h3><p>Аналог Git-индекса: у нас есть «главный» коммит с описанием работы, а поверх — пустой change, в который сыплются все текущие правки. По готовности части работы переносим изменения в основной коммит командой jj squash.</p><ol><li>jj new -m "feat: CSV parser" — создаём коммит с описанием работы.</li><li>jj new — поверх него создаём пустой коммит, в котором идёт работа.</li><li>Редактируем файлы. Всё попадает в текущий change (@).</li><li>jj squash -i — интерактивно выбираем, какие куски из @ переехать в родительский change. Это как git add -p, только работает и задним числом.</li></ol><h3>Edit workflow</h3><p>Противоположный подход: редактируем существующие коммиты напрямую. Создаём цепочку пустых коммитов с описаниями будущих кусочков работы, а потом командой jj edit &lt;change-id&gt; переключаемся между ними и дописываем содержимое. jj автоматически перестраивает потомков при каждом изменении.</p><p>Это встроенный interactive rebase без отдельной «фазы rebase»: вы просто редактируете средние коммиты истории, как если бы они были текущими. Ни тодо-файлов, ни «continue/abort» — всё делается обычными командами.</p><h2>Анонимные ветки и revsets</h2><p>Одно из самых непривычных для git-пользователя решений: <b>ветки в jj не обязаны иметь имена</b>. Вы можете начать эксперимент с новой идеей, не придумывая ничего вроде feature/experimental-cache-v2: если у двух коммитов один родитель — это уже ветвление, и для jj этого достаточно.</p><p>В Git всё, что не находится на именованной ветке, считается мусором и рано или поздно удаляется сборщиком («detached HEAD»). В jj мусора в этом смысле не бывает — все изменения равноправны, пока вы явно не сделаете jj abandon.</p><p>Имена в jj нужны только для push в Git-репозитории (GitHub, GitLab, etc.). Внутри Meta, где используют похожий VCS, по словам Стива, <i>«почти никто не заморачивается именами веток, когда привыкает»</i>.</p><h3>Revsets: язык запросов к истории</h3><p>Чтобы ссылаться на конкретные коммиты без имён, в jj есть <b>revsets</b> — DSL для запросов к графу истории. Примеры:</p><ul><li>@ — текущий change.</li><li>@- — родитель текущего change.</li><li>@+ — все прямые потомки.</li><li>trunk()..@ — всё, что было после ветвления от основной ветки (удобно смотреть свою работу).</li><li>description(bug) — все коммиты, где в описании есть слово «bug».</li><li>author("steve") — все коммиты Стива.</li><li>heads(all()) — все «концы» ветвлений в репозитории.</li></ul><p>Revsets комбинируются операторами: &amp; (пересечение), | (объединение), ~ (отрицание). Практический сценарий: нужно найти, где сломался тест, — пишете jj log -r "description(bug) &amp; author(me)", получаете список своих баг-фиксов. В Git для такого каждый пишет свой скрипт поверх git log --grep --author.</p><h2>First-class конфликты: как jj хранит их в истории</h2><p>Это нетривиальное архитектурное решение jj. В Git, если rebase упал на конфликт, процесс останавливается — вы фиксите файл, потом git rebase --continue, и так до конца цепочки. Если конфликт в середине, приходится разруливать его отдельно.</p><p>В jj конфликт — это <b>нормальное состояние коммита</b>. Он сохраняется в истории, не мешает дальнейшей работе, rebase идёт до конца и ничего не останавливает.</p><p>Что это даёт на практике:</p><ol><li><b>Rebase никогда не застревает.</b> Пересобираете 20 коммитов поверх нового main — получаете 20 коммитов, из которых помечены конфликтами только те, где реально столкнулись правки.</li><li><b>Конфликт можно отложить.</b> Создали новую работу поверх конфликтного коммита — jj корректно протаскивает конфликт через все потомки.</li><li><b>Автоматический rebase потомков.</b> Когда вы фиксите конфликт в @, все дочерние change автоматически перестраиваются — и, если их содержимое не пересекалось с конфликтным местом, они выходят из конфликтного состояния без ручного вмешательства.</li></ol><p>Пример из учебника: есть конфликтный коммит, поверх него — ещё один change (тоже в конфликте из-за наследования). Исправляете файл в родителе — и jj пишет:</p><p>Потомок вышел из конфликта сам. В Git такое разруливают вручную или через git rerere (опциональная фича «Reuse Recorded Resolution», запоминающая решения конфликтов для повторного применения).</p><h2>Operation log: почему в jj сложно потерять работу</h2><p>Git хранит историю коммитов, но не историю <i>операций</i>. Если вы случайно сделали git reset --hard и коммит не попал в reflog (или reflog протух), он пропал. В jj иначе: <b>каждая команда, меняющая состояние репо, пишется в operation log</b> и хранится по умолчанию 30 дней.</p><p>Любую операцию откатывает jj undo. В отличие от git reflog, который показывает только движения HEAD, jj лог — это полный журнал изменений репозитория, и любая точка в нём — валидное состояние, к которому можно откатиться.</p><p>Случайно сделали jj abandon на важном change? jj undo. Случайно перебазировали ветку не туда? jj undo. Хотите посмотреть, как репо выглядел час назад? jj op restore &lt;op-id&gt;.</p><h2>Что это меняет на практике</h2><h3>Stacked diffs без боли</h3><p><b>Stacked diffs</b> — это практика, когда большую фичу разбивают на цепочку мелких PR, каждый поверх предыдущего. В Git это требует сторонних инструментов (graphite, git-branchless) или ручного жонглирования с --onto. В jj — естественный режим: каждый change в цепочке — самостоятельный коммит, при изменении родителя все потомки перестраиваются автоматически. Для push на GitHub каждому коммиту цепочки достаётся имя через jj bookmark create.</p><h3>Interactive rebase — просто редактирование</h3><p>В Git git rebase -i — отдельный режим с тодо-файлом, в котором pick/squash/drop/reword. В jj это обычные команды: jj squash, jj abandon, jj describe &lt;change&gt;. Не нужен отдельный «режим rebase» — вы просто редактируете историю как данные.</p><h3>Staging area уходит — и не жалко</h3><p>Squash workflow воспроизводит поведение Git-индекса (отбор кусков правок), но делает это <i>задним числом</i>. Не нужно заранее решать, что попадёт в коммит — можно сначала написать код, потом через jj squash -i распределить куски по нужным change.</p><h2>Выводы</h2><p>jj — редкий случай, когда инструмент можно попробовать без риска: Git-бэкенд оставляет вам путь назад в любой момент, а новые концепции (change ID, first-class конфликты, op log) не требуют от команды ничего менять. Вы буквально можете работать с репозиторием через jj, пока коллега рядом пишет git commit.</p><p>Главная архитектурная ставка jj — перенести «операции с историей» из особых режимов (rebase, cherry-pick, reflog) в обычное редактирование графа коммитов. Если вы когда-либо путались в git rebase -i или теряли работу в git reset --hard — jj решает обе проблемы на уровне модели.</p><blockquote>Это и проще, и легче git — и при этом мощнее. Обычно в программировании нас учат, что есть компромиссы между этими свойствами. jj удаётся их избежать за счёт меньшего количества более мощных примитивов.</blockquote><p>Оригинал — <a href="https://steveklabnik.github.io/jujutsu-tutorial/">учебник Стива Клабника «Steve's Jujutsu Tutorial»</a>. В полной версии — ещё главы про named branches, работу с GitHub, кастомизацию templating-движка и продвинутые workflow (workspaces, colocated repositories). Документация проекта — <a href="https://jj-vcs.github.io/jj/latest/">jj-vcs.github.io/jj</a>.</p><p>Если хочется попробовать — возьмите любой свой Git-репозиторий и выполните jj git init --colocate. Флаг --colocate создаёт jj-репозиторий рядом с существующим .git/, не трогая историю: можно параллельно работать обоими CLI. Дальше — jj log и по учебнику.</p>]]></content:encoded>
    </item>
    <item>
      <title>5 git-команд, которые стоит запустить перед чтением чужого кода</title>
      <link>https://tproger.ru/translations/5-git-komand-kotorye-stoit-zapustit-pered-chteniem-chuzhogo-koda</link>
      <comments>https://tproger.ru/translations/5-git-komand-kotorye-stoit-zapustit-pered-chteniem-chuzhogo-koda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/5-git-komand-kotorye-stoit-zapustit-pered-chteniem-chuzhogo-koda</guid>
      <description><![CDATA[<p>Churn-анализ, bus factor, баг-хотспоты, commit velocity и hotfix-частота — 5 git-команд для полной диагностики незнакомого проекта за 2 минуты.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/5-git-komand-kotorye-stoit-zapustit-pered-chteniem-chuzhogo-koda">5 git-команд, которые стоит запустить перед чтением чужого кода</a>»</p>]]></description>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 09 Apr 2026 07:30:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Первое, что стоит сделать при знакомстве с новым проектом — не открывать код, а открыть терминал. Пять git-команд за пару минут покажут, кто писал проект, где скапливаются баги, растёт ли кодовая база или умирает — и какой файл все боятся трогать.</p><p>Это перевод <a href="https://piechowski.io/post/git-commands-before-reading-code/">статьи</a> Грега Пеховски, консультанта по аудиту кодовых баз. Его подход — диагностика проекта через историю коммитов, прежде чем читать хоть одну строку кода.</p><ul><li>Файлы с наибольшим churn (частотой изменений) — главные кандидаты на рефакторинг и источник багов</li><li>Один человек с 60%+ коммитов — bus factor, а если он ушёл полгода назад — это кризис</li><li>Пересечение churn-файлов и баг-файлов даёт точную карту самого рискованного кода</li><li>Количество коммитов по месяцам показывает, растёт проект или теряет команду</li><li>Частые revert и hotfix — сигнал проблем с CI/CD и тестированием</li></ul><h2>Что меняется чаще всего</h2><p>20 самых часто изменяемых файлов за последний год. Файл на первом месте — почти всегда тот, про который предупреждают: «А, этот файл. Его все боятся трогать».</p><p>Высокий churn (частота изменений) сам по себе не проблема — иногда это просто активная разработка. Но высокий churn у файла, за который никто не хочет отвечать — самый чёткий сигнал «тормозящего» кода. Это файл, где каждое изменение — патч на патч, а последствия мелкой правки непредсказуемы.</p><p><a href="https://www.microsoft.com/en-us/research/publication/use-of-relative-code-churn-measures-to-predict-system-defect-density/">Исследование Microsoft Research 2005 года</a> показало, что метрики на основе churn предсказывают дефекты надёжнее, чем метрики сложности кода. Автор рекомендует взять топ-5 файлов из этого списка и сверить их со списком баг-хотспотов (команда ниже). Файл, который одновременно high-churn и high-bug — главный риск проекта.</p><h2>Кто это написал</h2><p>Все контрибьюторы, отсортированные по числу коммитов. Если один человек — автор 60% и более коммитов, это bus factor. Если он ушёл полгода назад — это кризис.</p><p>Проверьте, кто активен за последние полгода:</p><p>Если топ-контрибьютор за всё время не появляется в полугодовом окне — это красный флаг, который стоит сразу обсудить с командой.</p><p>Смотрите и на «хвост» списка: 30 контрибьюторов всего, но только трое активны за последний год. Люди, которые строили систему — не те, кто её поддерживает.</p><p><b>Нюанс:</b> если команда использует squash-merge, команда покажет того, кто мержил, а не того, кто писал код. Уточните стратегию мержа, прежде чем делать выводы.</p><h2>Где скапливаются баги</h2><p>Та же структура, что и команда churn, но отфильтрованная по коммитам с ключевыми словами багов. Сравните этот список с churn-хотспотами: файлы, попавшие в оба списка — самый рискованный код. Они постоянно ломаются и постоянно патчатся, но никогда не чинятся по-настоящему.</p><p>Качество результата зависит от дисциплины коммит-сообщений. Если команда пишет «update stuff» на каждый коммит — ничего полезного не получите. Но даже грубая карта плотности багов лучше, чем никакой карты.</p><h2>Проект растёт или умирает</h2><p>Количество коммитов по месяцам за всю историю репозитория. Ищите паттерны:</p><ul><li>Ровный ритм — здоровый проект</li><li>Резкое падение вдвое за месяц — обычно кто-то ушёл</li><li>Нисходящая кривая за 6-12 месяцев — команда теряет темп</li><li>Всплески с тишиной между ними — пакетные релизы вместо непрерывной поставки</li></ul><blockquote>Однажды я показал CTO график коммитов его команды. Он сказал: «Это когда мы потеряли второго senior-инженера». Раньше он не связывал эти события. Это данные о команде, не о коде.</blockquote><h2>Как часто команда тушит пожары</h2><p>Частота revert и hotfix. Несколько за год — норма. Откаты каждые пару недель — команда не доверяет своему деплой-процессу. Это симптом глубже: ненадёжные тесты, отсутствие staging или пайплайн, в котором откат сложнее, чем должен быть.</p><p>Нулевой результат тоже сигнал: либо команда действительно стабильна, либо никто не пишет описательные коммит-сообщения.</p><p>Пять команд, пара минут. Они не расскажут всё, но покажут, какой код читать первым и что искать. Разница между методичным погружением в кодовую базу и бесцельным блужданием по файлам.</p><p>Оригинал: <a href="https://piechowski.io/post/git-commands-before-reading-code/">Git commands I run before reading any code</a>, Грег Пеховски.</p>]]></content:encoded>
    </item>
    <item>
      <title>Git: полный путеводитель — от первого коммита до продвинутых workflow</title>
      <link>https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor</link>
      <comments>https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor</guid>
      <description><![CDATA[<p>Всё о Git в одном месте: установка, команды, ветвление, rebase, hooks, работа в команде и GitHub. Полный навигационный гайд для разработчиков от Tproger.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor">Git: полный путеводитель — от первого коммита до продвинутых workflow</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Apr 2026 15:50:38 GMT</pubDate>
      <content:encoded><![CDATA[<p>Git — это распределённая система контроля версий, которая стала стандартом разработки программного обеспечения. Если вы пишете код, редактируете конфигурации, работаете с инфраструктурой или даже ведёте документацию — Git уже есть в вашем рабочем процессе или скоро появится. Эта статья — навигационный хаб: мы пройдём весь путь от базовых команд до продвинутых workflow и дадим ссылки на подробные разборы каждой темы.</p><p>— add / commit / push — три команды, покрывающие 80% ежедневной работы; остальное — ветвление и merge.</p><p>— Rebase линеаризует историю, merge сохраняет — выбор зависит от workflow команды, не от личных предпочтений.</p><p>— Git hooks позволяют автоматизировать проверки локально, до push — без настройки CI/CD.</p><p>— GitHub, GitLab, Bitbucket — платформы вокруг Git; сам Git работает локально и не зависит ни от одной из них.</p><p>— Reflog хранит историю HEAD 30–90 дней — даже «потерянный» после reset коммит можно восстановить.</p><h2>Что такое Git и зачем он нужен</h2><p>В 2005 году Линус Торвальдс создал Git для управления исходным кодом ядра Linux. До этого команда использовала проприетарную систему BitKeeper, но после конфликта с её владельцами Торвальдс написал собственную VCS за две недели. Главные требования: скорость, поддержка нелинейной разработки (тысячи параллельных веток) и полная распределённость.</p><p>В отличие от централизованных систем вроде SVN или CVS, где есть единственный сервер с полной историей, Git даёт каждому разработчику <b>полную копию репозитория</b> — со всей историей коммитов, ветками и тегами. Это означает, что вы можете работать офлайн, создавать ветки мгновенно и не зависеть от доступности сервера. Mercurial — ещё одна распределённая VCS — решал те же проблемы, но Git победил благодаря скорости, гибкости ветвления и экосистеме GitHub.</p><p>Главное преимущество распределённой модели — <b>отказоустойчивость и скорость</b>. Все операции, кроме push/pull, выполняются локально: создание ветки, коммит, просмотр истории, diff — всё работает мгновенно без сетевого подключения. Если центральный сервер упадёт, любой клон — полная резервная копия. В централизованных системах потеря сервера означает потерю всей истории.</p><p>Сегодня Git используют более 95% разработчиков по данным <a href="https://survey.stackoverflow.co/2024/technology/#1-version-control-systems">Stack Overflow Developer Survey</a>. Но Git — это только инструмент контроля версий, а не платформа для совместной работы. GitHub, GitLab и Bitbucket — это платформы, построенные <i>вокруг</i> Git. Подробнее о том, <a href="https://tproger.ru/translations/difference-between-git-and-github">в чём разница между Git и GitHub</a>, читайте в отдельной статье.</p><h2>Установка, настройка и первый репозиторий</h2><p>Git доступен на всех основных платформах. На macOS проще всего установить через Homebrew: brew install git. На Linux — через пакетный менеджер: sudo apt install git (Ubuntu/Debian) или sudo dnf install git (Fedora). На Windows — через официальный установщик с <a href="https://git-scm.com">git-scm.com</a> или менеджер пакетов: choco install git. Подробный разбор всех шагов — <a href="https://tproger.ru/translations/beginner-git-cheatsheet">от установки до первых команд</a>.</p><p>После установки убедитесь, что Git доступен, командой git --version — она выведет текущую версию и подтвердит, что всё работает.</p><p>После установки первым делом настройте имя и email — они будут записаны в каждый ваш коммит:</p><p>Теперь можно создать первый репозиторий. Команда git init превращает обычную папку в Git-репозиторий, создавая скрытую директорию .git со всей служебной информацией:</p><p>Файлы в Git проходят через три состояния: <b>рабочая директория</b> (working directory) — где вы редактируете файлы; <b>область подготовки</b> (staging area, она же index) — промежуточное хранилище для следующего коммита; <b>репозиторий</b> (.git) — постоянное хранилище всех коммитов. Понимание этого цикла — фундамент работы с Git.</p><p>Ещё несколько полезных настроек на старте: git config --global init.defaultBranch main — новые репозитории будут создаваться с веткой main вместо master. git config --global alias.st status — создаёт сокращение git st вместо полного git status. Алиасы экономят время при ежедневной работе: co для checkout, br для branch, lg для красивого лога.</p><h2>Основные команды: add, commit, log, diff</h2><p>Ежедневная работа с Git строится вокруг пяти команд. git add перемещает изменения в staging area. git commit фиксирует снимок. git status показывает текущее состояние. git log выводит историю. git diff показывает разницу между версиями. Если вы освоите только их — уже закроете 80% повседневных задач. Подробный <a href="https://tproger.ru/translations/git-quick-start">быстрый старт по основным операциям</a> собран в отдельном материале.</p><p>git add . добавляет все изменённые файлы разом, но аккуратнее добавлять конкретные файлы — так вы не затянете в коммит лишнее. Полезный вариант: git add -p — интерактивное добавление по частям (hunks), когда в одном файле несколько логически разных изменений.</p><p>Хороший коммит — атомарный: одно логическое изменение, понятное сообщение. Сообщение коммита состоит из заголовка (до 72 символов, отвечает на вопрос «что сделано») и опционального тела (через пустую строку, объясняет «почему»). Плохо: fix. Хорошо: fix: prevent crash when user has no avatar. Привычка писать осмысленные коммиты окупается при поиске багов через git log и git bisect.</p><p>Файл .gitignore определяет, какие файлы Git должен игнорировать: зависимости (node_modules/), артефакты сборки (dist/), секреты (.env). Без правильного .gitignore репозиторий быстро засоряется бинарниками и конфигурациями IDE. У нас есть <a href="https://tproger.ru/articles/gitignore-polnyj-gajd-s-wablonami-dlya-python-node-js-java-i">полный гайд по .gitignore</a> с готовыми шаблонами для Python, Node.js и Java. А для быстрой справки — <a href="https://tproger.ru/articles/5-shpargalok-po-git-ot-osnov-do-raboty-s-github">шпаргалки по Git-командам</a> на каждый день.</p><p>Команда git diff — главный инструмент для просмотра изменений. Без аргументов она показывает unstaged-изменения рабочей директории. git diff --cached (синоним --staged) — изменения, добавленные в индекс. Сравнение между ветками: git diff main feature/auth. Между конкретными коммитами: git diff a1b2c3d e4f5g6h. Добавьте --stat для краткой сводки по файлам.</p><h2>Ветвление и слияние</h2><p>Ветвление — одно из главных преимуществ Git. Создание ветки — это мгновенная операция: Git просто создаёт новый указатель на текущий коммит, не копируя файлы. Это позволяет работать над фичами, багфиксами и экспериментами параллельно, не мешая основной кодовой базе.</p><p>Git выполняет слияние двумя способами. <b>Fast-forward merge</b> происходит, когда целевая ветка является прямым предком исходной — то есть линейная история не расходилась — Git просто перемещает указатель вперёд. <b>3-way merge</b> (трёхстороннее слияние) используется, когда обе ветки содержат новые коммиты — Git находит общего предка и создаёт merge-коммит с двумя родителями.</p><p>Конфликты слияния возникают, когда обе ветки изменили одни и те же строки одного файла. Git помечает конфликтные участки маркерами &lt;&lt;&lt;&lt;&lt;&lt;&lt;, =======, &gt;&gt;&gt;&gt;&gt;&gt;&gt;. Вам нужно выбрать нужную версию (или объединить обе), удалить маркеры и закоммитить результат. Современные IDE вроде VS Code и IntelliJ имеют визуальные инструменты для разрешения конфликтов — используйте их вместо ручного редактирования.</p><p>Чтобы минимизировать конфликты, регулярно подтягивайте изменения из основной ветки в свою feature-ветку: git merge main или git rebase main. Чем дольше ветка живёт изолированно, тем больше конфликтов при слиянии. Оптимальная длительность feature-ветки — от нескольких часов до пары дней.</p><p>Ненужную ветку удаляют командой git branch -d feature/auth (флаг -D — принудительное удаление, даже если ветка не слита). Переименование — git branch -m old-name new-name. Чтобы обновить remote, удалите старую ветку и запушьте новую: git push origin --delete old-name &amp;&amp; git push -u origin new-name.</p><p>Для практики ветвления рекомендуем интерактивный тренажёр <a href="https://learngitbranching.js.org/?locale=ru_RU">Learn Git Branching</a> — он визуализирует дерево коммитов и помогает понять, как работают merge, rebase и cherry-pick.</p><h2>Удалённая работа: remote, push, pull, fetch</h2><p>Локальный репозиторий — это полная копия проекта, но для командной работы нужен <b>remote</b> — удалённый репозиторий на сервере (GitHub, GitLab, свой сервер). Команда git clone создаёт локальную копию удалённого репозитория и автоматически настраивает remote с именем origin.</p><p>Важно понимать разницу между git pull и git fetch. fetch скачивает новые коммиты с сервера, но <b>не изменяет</b> вашу рабочую ветку — вы можете спокойно посмотреть, что изменилось, через git log origin/main. pull — это fetch + merge в одну команду: скачивает и сразу сливает. Подробный разбор — <a href="https://tproger.ru/explain/git-pull-and-git-fetch-whats-the-difference">разница между pull и fetch</a>.</p><p>При командной работе вы часто столкнётесь с tracking-ветками. Когда вы делаете git push -u origin feature/auth, флаг -u связывает локальную ветку с удалённой. После этого достаточно писать просто git push и git pull без указания remote и ветки.</p><p>Совет: используйте git pull --rebase вместо обычного pull — так вы избежите лишних merge-коммитов при синхронизации с удалённой веткой. Это можно сделать поведением по умолчанию: git config --global pull.rebase true. Подходит не всем командам — если для вас важна полная история ветвлений (например, для аудита), оставьте обычный merge при pull.</p><h2>Отмена изменений: revert, reset, stash</h2><p>Ошибки в Git — не катастрофа. Система предлагает несколько инструментов для отмены изменений на разных этапах: от незакоммиченных правок до опубликованных коммитов. Разберём основные сценарии.</p><p><b>git revert</b> — безопасная отмена. Создаёт новый коммит, который отменяет изменения указанного коммита. Не переписывает историю, подходит для публичных веток:</p><p><b>git reset</b> — откат истории. Перемещает указатель ветки на указанный коммит. Три режима определяют, что происходит с файлами:</p><ul><li>--soft — коммит убирается, но изменения остаются в staging area. Удобно, если хотите переделать коммит.</li><li>--mixed (по умолчанию) — коммит убирается, изменения остаются в рабочей директории, но не в staging.</li><li>--hard — коммит убирается, все изменения удаляются. <b>Осторожно:</b> это необратимо для незакоммиченных правок.</li></ul><p><b>git stash</b> — временное хранилище. Прячет незакоммиченные изменения, чтобы переключиться на другую задачу, и позволяет вернуть их позже. Подробнее — <a href="https://tproger.ru/articles/git-stash-kak-sohranit-i-vosstanovit-nezakommichennye-izmeneni">как сохранить незакоммиченные изменения</a>.</p><p>О <b>detached HEAD</b> стоит знать отдельно. Это состояние, когда HEAD указывает не на ветку, а на конкретный коммит. Любые новые коммиты в этом состоянии не принадлежат ни одной ветке и будут потеряны при переключении. Решение: создайте ветку командой git switch -c branch-name. Ещё больше сценариев разобрано в статье про <a href="https://tproger.ru/translations/most-common-git-screwupsquestions-and-solutions">типичные ошибки и как их исправить</a>, а практические приёмы — в материале про <a href="https://tproger.ru/translations/problems-with-git">Git-команды для исправления ошибок</a>. Детальное сравнение инструментов отката — <a href="https://tproger.ru/articles/kak-otkatit-kommit-v-git-reset-revert-checkout">reset, revert и checkout на практике</a>.</p><h2>Rebase, cherry-pick и переписывание истории</h2><p>git rebase переносит цепочку коммитов на новую базу. Вместо merge-коммита вы получаете линейную историю — как будто ваши изменения были сделаны поверх последней версии основной ветки. Это делает историю чище и проще для чтения.</p><p>Interactive rebase (git rebase -i) — мощный инструмент для «причёсывания» истории перед публикацией. Вы можете склеить несколько коммитов в один (squash), переформулировать сообщения (reword), удалить коммиты (drop) или изменить их порядок.</p><p><b>Золотое правило:</b> никогда не ребейсите ветки, которые уже запушены и используются другими разработчиками. Rebase переписывает хеши коммитов, и у коллег возникнут конфликты при следующем pull. Rebase — для локальных, ещё не опубликованных коммитов.</p><p>git cherry-pick копирует конкретный коммит из одной ветки в другую. Полезно, когда нужно перенести один багфикс без слияния всей ветки:</p><p>git reflog — «чёрный ящик» Git. Хранит историю перемещений HEAD: 90 дней для достижимых коммитов и 30 дней для недостижимых (после reset или rebase). Даже «потерянный» коммит можно найти через reflog и восстановить — но не тяните дольше месяца. Больше о cherry-pick и других полезных командах — в статье <a href="https://tproger.ru/translations/git-tips-and-tricks">cherry-pick и другие полезные команды</a>. О выборе между rebase и merge — отдельный разбор: <a href="https://tproger.ru/articles/git-rebase-vs-merge-kogda-chto-ispolzovat-i-v-chyom-raznica">когда rebase, а когда merge</a>.</p><p>Для массового переписывания истории используют git filter-branch или его современную замену — git filter-repo (устанавливается отдельно через pip install git-filter-repo). Типичные сценарии: удалить случайно закоммиченный пароль, сменить email автора во всех коммитах, вырезать крупный бинарный файл из истории. После переписывания истории потребуется git push --force. Безопаснее использовать git push --force-with-lease — эта команда отвергнет push, если remote-ветка обновилась после вашего последнего fetch, защищая от случайной перезаписи чужих коммитов.</p><h2>Теги, релизы и версионирование</h2><p>Теги — это именованные указатели на конкретные коммиты, обычно используемые для маркировки релизов. В Git есть два типа тегов: <b>lightweight</b> (просто указатель, как закладка) и <b>annotated</b> (полноценный объект с автором, датой и сообщением). Для релизов всегда используйте аннотированные теги:</p><p>Стандартная схема версионирования — <b>Semantic Versioning</b> (SemVer): MAJOR.MINOR.PATCH. MAJOR увеличивается при несовместимых изменениях API, MINOR — при новой функциональности с обратной совместимостью, PATCH — при багфиксах. Например, v2.1.3 означает вторую мажорную версию, первое минорное обновление и третий патч.</p><p>На GitHub теги автоматически превращаются в <b>Releases</b> — страницы с описанием изменений, бинарными файлами для скачивания и автоматически сгенерированными release notes на основе коммитов. Вы можете привязать к релизу скомпилированные бинарники, архивы, Docker-образы — всё, что нужно пользователям для установки конкретной версии.</p><p>Полезная практика — автоматизировать создание релизов. Инструменты вроде <b>semantic-release</b> и <b>release-please</b> анализируют коммиты в формате Conventional Commits и автоматически определяют следующий номер версии, генерируют CHANGELOG и создают GitHub Release. Это убирает человеческий фактор из процесса версионирования.</p><p>Переключиться на тег можно командой git checkout v1.2.0 или git switch --detach v1.2.0 — вы окажетесь в состоянии <b>detached HEAD</b>. Чтобы начать работу от тега, создайте ветку: git checkout -b hotfix/v1.2.1 v1.2.0. Ещё одна полезная конвенция — файл CITATION.cff в корне репозитория: GitHub распознаёт его и показывает кнопку «Cite this repository», что важно для научных и open-source-проектов.</p><h2>Git Hooks: автоматизация проверок</h2><p>Git hooks — это скрипты, которые Git автоматически запускает при определённых событиях: перед коммитом, после push, при получении изменений. Они позволяют автоматизировать проверки качества кода без настройки CI/CD. Подробный разбор — <a href="https://tproger.ru/articles/git-hooks-avtomatizaciya-proverok-pered-kommitom-i-puwem">автоматизация проверок с Git hooks</a>.</p><p>Основные клиентские хуки:</p><ul><li>pre-commit — запускается перед коммитом. Типичное использование: линтинг, форматирование, проверка секретов.</li><li>commit-msg — проверяет сообщение коммита. Например, соответствие формату Conventional Commits.</li><li>pre-push — запускается перед push. Можно прогнать тесты, чтобы не отправлять сломанный код.</li></ul><p>Серверные хуки (pre-receive, post-receive) выполняются на стороне сервера и контролируют, какие push-запросы принимать. Они используются для enforce-политик: запрет force push в main, обязательные code review и т.д.</p><p>Среди менее известных, но полезных хуков: post-checkout — срабатывает после git checkout или git switch и удобен для автоматической переустановки зависимостей при переключении веток (например, npm install если изменился package-lock.json). post-update — серверный хук, выполняется после обновления refs; используется для отправки уведомлений или триггера деплоя.</p><p>Проблема хуков — они хранятся в .git/hooks/ и не попадают в репозиторий. Инструменты вроде <b>Husky</b> (JavaScript), <b>pre-commit</b> (Python) и <b>Lefthook</b> (Go, универсальный) решают эту проблему: хуки описываются в конфигурационном файле, который коммитится в репозиторий, и автоматически устанавливаются при npm install или аналогичной команде.</p><h2>Продвинутые инструменты</h2><p>За пределами ежедневных команд Git предлагает специализированные инструменты для нетривиальных задач. Знать их все не обязательно, но когда они нужны — они экономят часы работы.</p><h3>git bisect</h3><p><b>git bisect</b> — бинарный поиск коммита, сломавшего код. Вы указываете «хороший» и «плохой» коммит, а Git автоматически переключается между ними, сужая диапазон, пока не найдёт виновника. Незаменим, когда баг появился «где-то на прошлой неделе»:</p><h3>git worktree</h3><p><b>git worktree</b> позволяет иметь несколько рабочих директорий одного репозитория одновременно. Вместо git stash + переключения ветки вы можете открыть вторую ветку в отдельной папке и работать параллельно. Без флага -b команда работает только для уже существующей ветки:</p><h3>git lfs</h3><p><b>git lfs</b> (Large File Storage) — расширение для работы с большими файлами (изображения, видео, модели ML). Вместо хранения бинарников в истории Git, LFS заменяет их указателями и хранит сами файлы на отдельном сервере. Без LFS репозиторий с бинарниками быстро разрастается до гигабайтов.</p><h3>git submodule</h3><p><b>git submodule</b> — вложенные репозитории. Позволяют включить один Git-репозиторий в другой как зависимость с фиксированной версией. Полезно для монорепозиториев и shared-библиотек, но сложно в обслуживании — многие команды предпочитают альтернативы вроде пакетных менеджеров.</p><h3>git blame и .gitattributes</h3><p><b>git blame</b> показывает, кто и когда изменил каждую строку файла. Незаменим для понимания контекста изменений — вместо вопроса «кто это написал?» вы сразу видите автора, дату и коммит. В IDE есть встроенные аналоги (Git Lens в VS Code, Annotate в IntelliJ). <b>git format-patch</b> и <b>git apply</b> позволяют экспортировать и импортировать изменения как файлы-патчи — полезно для передачи изменений без доступа к общему remote.</p><p>Файл .gitattributes управляет атрибутами путей в репозитории. Главное применение — нормализация переносов строк: строка * text=auto автоматически конвертирует CRLF в LF при коммите — критично для команд, где Windows- и Linux-разработчики работают над одним кодом. Также через .gitattributes отмечают бинарные файлы (*.png binary), выбирают алгоритм diff для конкретных типов (*.py diff=python) и настраивают стратегии merge.</p><h2>Работа в команде: workflow и best practices</h2><p>Git — гибкий инструмент, и без договорённостей в команде он быстро превращается в хаос. Workflow — это набор правил, определяющий, как команда работает с ветками, коммитами и релизами.</p><h3>Git Flow, GitHub Flow и Trunk-Based</h3><p>Три основных подхода — <a href="https://tproger.ru/articles/git-flow-github-flow-i-trunk-based-development-kakoj-workflow">Git Flow, GitHub Flow и Trunk-Based Development</a>:</p><ul><li><b>Git Flow</b> — формальная модель с ветками develop, release, hotfix. Подходит для проектов с чётким циклом релизов (мобильные приложения, десктопный софт).</li><li><b>GitHub Flow</b> — упрощённый: main + feature-ветки + pull requests. Подходит для web-проектов с непрерывным деплоем.</li><li><b>Trunk-Based Development</b> — все работают в main, feature-ветки живут максимум 1–2 дня. Требует зрелой культуры CI/CD и feature flags.</li></ul><h3>Conventional Commits</h3><p><b>Conventional Commits</b> — формат сообщений коммитов, который структурирует историю и позволяет автоматически генерировать changelogs. Шаблон: type(scope): description. Основные типы: feat (новая фича), fix (багфикс), docs, refactor, test, chore.</p><p><b>Именование веток</b> — ещё одна важная конвенция. Распространённая схема: type/description, например feature/user-auth, fix/login-crash, chore/update-deps. Если команда использует трекер — добавляйте номер задачи: feat/PROJ-123_user-auth.</p><p><b>Code review через pull requests</b> — обязательная практика. PR (pull request) или MR (merge request в GitLab) — это предложение слить вашу ветку в основную. Коллеги проверяют код, оставляют комментарии, предлагают изменения. Хороший PR: небольшой и фокусированный, с описанием «зачем», скриншотами UI-изменений и ссылкой на задачу в трекере.</p><p>Защита веток (<b>branch protection rules</b>) — ещё один уровень безопасности. Можно запретить push напрямую в main, потребовать минимум один approve на PR, обязательное прохождение CI-пайплайна перед merge. Это предотвращает случайные поломки продакшена и формализует процесс доставки кода. Гит интегрируется в контекст DevOps — подробнее об этом в <a href="https://tproger.ru/articles/roadmap-devops-inzhenera-v-2026-godu--chto-uchit-i-v-kakom-poryadke">Git в контексте DevOps-инженерии</a>.</p><p>Файл CONTRIBUTING.md в корне репозитория описывает правила контрибуции: как форкнуть проект, стиль кода, требования к тестам, оформление PR. GitHub автоматически показывает ссылку на него при создании issue и pull request. Весь текст в GitHub-экосистеме оформляется на <b>Markdown</b> — языке разметки с простым синтаксисом: заголовки, списки, блоки кода, таблицы, task lists (- [x] Готово), @mentions коллег. <b>GitHub Flavored Markdown</b> (GFM) расширяет стандартный Markdown автолинковкой URL, зачёркиванием и таблицами.</p><h2>Платформы для хостинга Git-репозиториев</h2><p>Все навыки Git из этой статьи работают с любой платформой — Git универсален, меняется только хостинг. Выбор платформы зависит от команды, юрисдикции и требований к инфраструктуре.</p><h3>Облачные платформы</h3><p><b>GitHub</b> — крупнейшая платформа для хостинга Git-репозиториев с более чем 100 млн разработчиков. Основные инструменты: <b>Pull Requests</b> для code review, <b>Issues</b> для трекинга задач, <b>Actions</b> для CI/CD, <b>Pages</b> для статических сайтов и <b>Copilot</b> — ИИ-ассистент для написания кода. Регистрация бесплатна, для open-source используется Fork → PR workflow. Подробнее — <a href="https://tproger.ru/articles/how-to-prepare-your-github-profile">как оформить профиль на GitHub</a>.</p><p><b>GitLab</b> — DevOps-платформа «всё в одном»: CI/CD, реестр контейнеров, мониторинг, управление проектами, Wiki. Доступна как облако и как self-hosted (Community Edition бесплатна). Особенно популярна в корпоративных окружениях, где нужна вся цепочка разработки в одном месте.</p><p><b>Bitbucket</b> — платформа от Atlassian, тесно интегрированная с Jira и Confluence. Поддерживает Pipelines (CI/CD), Code Insights и branch permissions. Бесплатна для команд до 5 человек. Если команда уже работает в экосистеме Atlassian — Bitbucket будет естественным выбором.</p><p><b>GitVerse</b> (<a href="https://gitverse.ru">gitverse.ru</a>) — платформа от Сбера: хостинг репозиториев, CI/CD, code review. Подходит для команд, которым важна локальная юрисдикция хранения данных.</p><p><b>GitFlic</b> (<a href="https://gitflic.ru">gitflic.ru</a>) — Git-хостинг с приватными репозиториями и встроенным CI/CD. Поддерживает стандартный Git-workflow, есть бесплатный тарифный план.</p><h3>Self-hosted решения</h3><p><b>GitLab CE</b> (Community Edition) — бесплатная версия GitLab, которую можно развернуть на собственном сервере, в Yandex Cloud, VK Cloud или любом другом облаке. Полный контроль над данными и инфраструктурой.</p><p><b>Gitea</b> (<a href="https://gitea.com">gitea.com</a>) — лёгкий open-source Git-сервер на Go. Быстрее и проще GitLab, подходит для небольших команд. Занимает минимум ресурсов и разворачивается за минуты.</p><p><b>Codeberg</b> (<a href="https://codeberg.org">codeberg.org</a>) — некоммерческий хостинг на базе Gitea. Бесплатный и полностью открытый — подходит для open-source проектов и разработчиков, которые предпочитают некоммерческую инфраструктуру.</p><h3>GitHub Actions и CI/CD</h3><p><b>GitHub Actions</b> — встроенная система CI/CD прямо в репозитории. Workflow описываются в YAML-файлах в директории .github/workflows/ и запускаются автоматически при определённых событиях.</p><p>Ключевые концепции GitHub Actions:</p><ul><li><b>Triggers</b> — события, запускающие workflow: push, pull_request, schedule (cron), workflow_dispatch (ручной запуск)</li><li><b>Runners</b> — среда выполнения: GitHub-hosted (ubuntu-latest, windows-latest, macos-latest) или self-hosted для собственных серверов</li><li><b>Secrets</b> — зашифрованные переменные окружения, доступные через ${{ secrets.API_KEY }}. Хранятся в настройках репозитория</li><li><b>Артефакты и кеш</b> — сохранение результатов сборки между запусками и кеширование зависимостей для ускорения pipeline</li></ul><p>Подробнее о CI/CD и смежных практиках — в нашем <a href="https://tproger.ru/articles/roadmap-devops-inzhenera-v-2026-godu--chto-uchit-i-v-kakom-poryadke">roadmap DevOps-инженера</a>.</p><h3>GitHub Pages, Copilot и другие инструменты</h3><p><b>GitHub Pages</b> — бесплатный хостинг статических сайтов прямо из репозитория. Поддерживает Jekyll из коробки, custom domains и автоматический SSL. Для привязки своего домена достаточно создать файл CNAME и настроить DNS.</p><p><b>GitHub Copilot</b> — ИИ-ассистент, который подсказывает код прямо в IDE. Работает в VS Code, JetBrains, Neovim и других редакторах.</p><p><b>Security</b> — набор инструментов для безопасности: <b>Dependabot</b> автоматически обновляет зависимости и предупреждает об уязвимостях, <b>code scanning</b> и <b>secret scanning</b> ищут уязвимости и утёкшие секреты в коде.</p><p><b>GitHub CLI</b> (gh) — работа с GitHub из терминала: создание PR, просмотр Issues, управление Actions. <b>Packages</b> — реестр пакетов (npm, Docker, Maven). <b>Projects</b> — встроенное управление задачами с Kanban-доской и таймлайном.</p><h2>Git на собеседованиях</h2><p>Git-вопросы встречаются на собеседованиях на позиции любого уровня — от junior до senior. Не потому что нужно знать все команды наизусть, а потому что Git отражает понимание процессов разработки. Вот типичные вопросы и на что обращают внимание:</p><ul><li><b>Rebase vs merge — когда что?</b> Ожидают: merge для публичных веток (сохраняет историю), rebase для локальных feature-веток (чистая история). Золотое правило rebase.</li><li><b>Reset vs revert — в чём разница?</b> Ожидают: revert безопасен (новый коммит), reset переписывает историю. Reset --soft/--mixed/--hard.</li><li><b>Что такое fast-forward merge?</b> Ожидают: линейное перемещение указателя без merge-коммита, возможно когда ветка «впереди» без расхождений.</li><li><b>Что такое detached HEAD?</b> Ожидают: HEAD указывает на коммит, а не на ветку. Коммиты будут потеряны без создания ветки.</li><li><b>Как работает cherry-pick?</b> Ожидают: копирует один коммит в текущую ветку с новым хешем. Сценарии использования.</li><li><b>Что такое stash и когда его использовать?</b> Ожидают: временное хранилище незакоммиченных изменений. Сценарий — переключение контекста.</li></ul><p>На senior-позициях вопросы глубже: как устроен Git изнутри (DAG, объекты: blob, tree, commit, tag), стратегии ветвления для микросервисов, как настроить защиту веток (branch protection rules), как организовать монорепозиторий. Могут попросить нарисовать дерево коммитов после серии операций merge/rebase/cherry-pick.</p><p><b>Как готовиться.</b> Практикуйтесь на реальных проектах — создайте тестовый репозиторий и воспроизведите каждый сценарий: конфликт слияния, interactive rebase, bisect. Отработайте ответы на вопросы вслух — на собеседовании важна не только правильность, но и уверенность.</p><h2>Куда двигаться дальше</h2><p>Если вы только начинаете путь в Git — рекомендуем пошаговый курс <a href="https://tproger.ru/curriculum/git-guide">как выучить Git с нуля</a>, где разобран оптимальный порядок изучения. Для глубокого погружения — бесплатная книга <a href="https://git-scm.com/book/ru/v2">Pro Git</a> на русском языке, охватывающая всё от основ до внутреннего устройства Git.</p><p>Следующие направления для изучения: <b>GitOps</b> — управление инфраструктурой через Git-репозитории (ArgoCD, Flux), когда состояние кластера описано в Git и автоматически синхронизируется; <b>CI/CD</b> — автоматизация сборки, тестирования и деплоя (GitHub Actions, GitLab CI, Jenkins); <b>монорепозитории</b> — управление несколькими проектами в одном репозитории (Nx, Turborepo, Bazel).</p><p>Начните с трёх команд (add, commit, push), затем освойте ветвление и merge. Когда почувствуете уверенность — переходите к rebase и hooks. Каждая ссылка в этом путеводителе ведёт на детальный разбор с примерами кода.</p>]]></content:encoded>
    </item>
    <item>
      <title>.gitignore: полный гайд с шаблонами для Python, Node.js, Java и Go</title>
      <link>https://tproger.ru/articles/gitignore-polnyj-gajd-s-wablonami-dlya-python-node-js-java-i</link>
      <comments>https://tproger.ru/articles/gitignore-polnyj-gajd-s-wablonami-dlya-python-node-js-java-i?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/gitignore-polnyj-gajd-s-wablonami-dlya-python-node-js-java-i</guid>
      <description><![CDATA[<p>Синтаксис .gitignore, готовые шаблоны для Python, Node.js, Java и Go, глобальный gitignore, git rm --cached и gitignore.io. Разбираем с примерами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/gitignore-polnyj-gajd-s-wablonami-dlya-python-node-js-java-i">.gitignore: полный гайд с шаблонами для Python, Node.js, Java и Go</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Apr 2026 15:26:53 GMT</pubDate>
      <content:encoded><![CDATA[<p>.gitignore — это файл, который сообщает Git, какие файлы и директории не нужно отслеживать.</p><p>Файл .gitignore — один из первых, который появляется в любом репозитории. Но многие добавляют его по привычке, не разбираясь в синтаксисе и не думая о глобальных настройках. В итоге в историю коммитов попадают .pyc-файлы, папки node_modules и секреты из .env.</p><p>В этом гайде разберём синтаксис .gitignore с примерами каждого паттерна, дадим готовые шаблоны для Python, Node.js, Java и Go, а также покажем, как исправить ситуацию, если файл уже попал в индекс. Статья рассчитана на тех, кто уже знаком с основами Git — если нужно освежить базу, начните с <a href="https://tproger.ru/translations/beginner-git-cheatsheet">введения в Git</a>.</p><p>— .gitignore поддерживает паттерны *, **, !, / и комментарии через #</p><p>— Готовые шаблоны для Python, Node.js, Java и Go закрывают 90% типичных случаев</p><p>— Глобальный ~/.gitignore_global избавляет от повторения в каждом проекте правил для IDE и ОС</p><p>— Если файл уже в индексе, git rm --cached убирает его без удаления с диска</p><p>— .gitkeep — хак для отслеживания пустых директорий</p><p>Эта статья — часть нашего <a href="https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor">полного путеводителя по Git</a>. Там — весь маршрут: от первого коммита до продвинутых workflow.</p><h2>Синтаксис .gitignore: разбираем каждый паттерн</h2><p>Git читает .gitignore построчно. Пустые строки игнорируются, строки с # в начале — комментарии. Остальное — паттерны.</p><p><b>* — любое количество символов в имени файла</b> (кроме /):</p><p><b>** — любое количество директорий</b> (рекурсивно):</p><p><b>! — отмена предыдущего правила</b> (исключение из исключений):</p><p><b>Важно:</b> паттерн ! не работает, если родительская директория уже заигнорирована. Например, если в .gitignore есть строка build/, то правило !build/keep-me.txt не поможет — файл всё равно будет игнорироваться. Чтобы исключение сработало, нужно сначала разрешить саму директорию: !build/, а затем уже — конкретный файл.</p><p><b>/ в начале — привязка к корню репозитория</b>:</p><p><b>/ в конце — игнорировать только директорию</b>, не файл с таким же именем:</p><p><b># — комментарий</b>. Используйте для группировки правил:</p><h2>Шаблон .gitignore для Python</h2><p>Python генерирует .pyc-файлы и папки __pycache__ при каждом запуске. Виртуальные окружения (venv, .venv) и файлы с переменными окружения (.env) тоже не должны попадать в репозиторий.</p><h2>Шаблон .gitignore для Node.js</h2><p>Главная причина тяжёлых репозиториев на Node.js — папка node_modules, которую забыли добавить в .gitignore. Её размер легко достигает сотен мегабайт.</p><h2>Шаблон .gitignore для Java</h2><p>Java-проекты собираются Maven или Gradle — у каждого свои папки артефактов. Скомпилированные .class-файлы и .jar-архивы пересобираются при каждом билде и в репозитории не нужны.</p><h2>Шаблон .gitignore для Go</h2><p>Go компилирует проект в бинарник — его хранить в репозитории не нужно. Папка vendor/ содержит копии зависимостей: её включать или нет — зависит от политики команды. Если используете Go modules без vendor-режима, добавьте папку в .gitignore.</p><h2>Глобальный .gitignore: один раз для всех проектов</h2><p>Некоторые файлы мусорят в любом проекте — .DS_Store на macOS, Thumbs.db на Windows, файлы IDE вроде .idea/ или .vscode/. Дублировать эти правила в каждом репозитории неудобно. Для этого есть глобальный .gitignore.</p><p>Настройка через core.excludesFile:</p><p>Пример содержимого ~/.gitignore_global:</p><p>После настройки Git применяет глобальные правила автоматически во всех репозиториях на вашем компьютере — без изменения .gitignore проекта.</p><p>Ещё один способ локально игнорировать файлы — .git/info/exclude. Этот файл работает как .gitignore, но не коммитится в репозиторий и виден только вам. Удобно для временных файлов, специфичных для вашего окружения, которые не стоит выносить в глобальный ~/.gitignore_global.</p><h2>Файл уже в индексе: как перестать его отслеживать</h2><p>Добавить правило в .gitignore недостаточно, если файл уже был закоммичен. Git продолжит его отслеживать. Нужно убрать файл из индекса, сохранив его на диске:</p><p>После этого добавьте правило в .gitignore и закоммитьте оба изменения — удаление из индекса и обновлённый .gitignore. Сам файл останется у вас на диске, но перестанет появляться в git status.</p><p>Если нужно очистить весь индекс и применить правила заново (например, после добавления нескольких паттернов):</p><p><b>Внимание:</b> эта команда пересоздаёт индекс целиком. Не запускайте её при незакоммиченных изменениях.</p><h2>.gitkeep: как отслеживать пустые директории</h2><p>Git не отслеживает директории — только файлы. Если папка пустая, git add её просто проигнорирует. Это проблема, когда структура директорий важна для проекта: например, logs/, uploads/, tmp/.</p><p>Решение — добавить в пустую папку файл-заглушку .gitkeep:</p><p>Файл .gitkeep — неофициальное соглашение. Никакой специальной поддержки в Git нет, это просто пустой файл с понятным именем. Некоторые команды используют .githold или .keep — принципиальной разницы нет.</p><h2>Инструменты: генераторы готовых шаблонов</h2><p>Не обязательно писать .gitignore с нуля — есть готовые инструменты:</p><ul><li><a href="https://www.toptal.com/developers/gitignore">gitignore.io</a> (toptal.com/developers/gitignore) — генератор по языку, IDE и ОС. Введите «Python», «JetBrains», «macOS» — получите готовый файл.</li><li><a href="https://github.com/github/gitignore">GitHub gitignore templates</a> — официальная коллекция шаблонов от GitHub. Шаблоны для 150+ языков и фреймворков. Используется как основа при создании репозитория через интерфейс GitHub.</li><li>gh repo create — при создании репозитория через GitHub CLI можно сразу выбрать шаблон .gitignore флагом --gitignore.</li></ul><p>Для проверки, почему конкретный файл игнорируется (или не игнорируется), используйте встроенную команду:</p><h2>Итог</h2><p>Правильный .gitignore — это не формальность, а часть культуры работы с репозиторием. Он защищает от утечки секретов, не даёт захламить историю коммитов и экономит время при клонировании. Начните с шаблона под ваш стек (используйте gitignore.io или GitHub-коллекцию), добавьте глобальный файл для настроек IDE, и у вас не будет проблем с лишними файлами в git status.</p><p>Если хотите разобраться с Git глубже — изучите <a href="https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor">полный путеводитель по Git</a> на Tproger: там собраны все ключевые темы от основ до продвинутых техник.</p>]]></content:encoded>
    </item>
    <item>
      <title>Git Flow, GitHub Flow и Trunk-Based Development: какой workflow выбрать</title>
      <link>https://tproger.ru/articles/git-flow-github-flow-i-trunk-based-development-kakoj-workflow</link>
      <comments>https://tproger.ru/articles/git-flow-github-flow-i-trunk-based-development-kakoj-workflow?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/git-flow-github-flow-i-trunk-based-development-kakoj-workflow</guid>
      <description><![CDATA[<p>Сравниваем Git Flow, GitHub Flow, Trunk-Based и GitLab Flow: отличия, плюсы, минусы и критерии выбора для вашей команды. С ASCII-схемами и таблицей.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/git-flow-github-flow-i-trunk-based-development-kakoj-workflow">Git Flow, GitHub Flow и Trunk-Based Development: какой workflow выбрать</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Apr 2026 15:25:05 GMT</pubDate>
      <content:encoded><![CDATA[<p>Когда команда только начинает использовать Git, все коммитят в main — и это работает. Но с ростом числа разработчиков, выпусков и параллельных задач хаос нарастает: кто-то сломал сборку, хотфикс застрял в незарелизенной ветке, никто не знает, что попадёт в следующий релиз. Решение — договориться о workflow: наборе правил, как создавать ветки, когда сливать и что идёт в прод.</p><p>Существует несколько устоявшихся подходов: Git Flow, GitHub Flow, Trunk-Based Development и GitLab Flow. У каждого свои сильные стороны и ограничения. Разберём, чем они отличаются и какой выбрать для вашей команды.</p><p>— Git Flow оправдан для продуктов с длинными релизными циклами (мобильные приложения, коробочное ПО).</p><p>— GitHub Flow — простой выбор для SaaS и веб-команд с CI/CD: одна ветка main + короткоживущие фичи.</p><p>— Trunk-Based Development максимизирует скорость деплоя, но требует зрелой инфраструктуры: feature flags, автотесты, быстрый CI.</p><p>— GitLab Flow — компромисс между Git Flow и Trunk-Based: environment-ветки без сложных release-веток.</p><p>— Начните с GitHub Flow и переходите на Trunk-Based по мере роста CI/CD-зрелости команды.</p><p>Эта статья — часть нашего <a href="https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor">полного путеводителя по Git</a>. Там — весь маршрут: от первого коммита до продвинутых workflow.</p><h2>Git Flow: строгая структура для долгих релизов</h2><p>Git Flow — самый известный workflow, описанный Винсентом Дриссеном в 2010 году. Его основа — две постоянные ветки: main (всегда стабильна, только теги релизов) и develop (интеграционная ветка). Поверх них — три типа временных веток.</p><ul><li><b>feature/*</b> — новые функции, ответвляются от develop, сливаются обратно</li><li><b>release/*</b> — подготовка релиза: только баг-фиксы, документация, версии; сливается в main и develop</li><li><b>hotfix/*</b> — срочные фиксы прямо из main; сливается и в main, и в develop</li></ul><p><b>Когда оправдан:</b> мобильная разработка (App Store review занимает дни), коробочное ПО с поддержкой нескольких версий, enterprise-продукты с квартальными релизными циклами. Команда знает: в main только то, что уже у пользователей.</p><p><b>Минусы:</b> тяжёлый для SaaS с деплоем несколько раз в день — слишком много веток, слишком много merge'ей. Ветки живут долго, накапливают конфликты. Инструмент git flow упрощает работу, но не убирает сложность модели.</p><h2>GitHub Flow: простота для непрерывной поставки</h2><p>GitHub Flow появился как реакция на сложность Git Flow. Правило одно: main всегда готов к деплою, новые фичи — в короткоживущих ветках через PR.</p><ul><li>Создаёте ветку от main с понятным именем (fix/login-timeout, feat/dark-mode)</li><li>Коммитите, открываете Pull Request — это точка обсуждения и code review</li><li>После approve'а и прохождения CI — мёрж в main и деплой</li></ul><p><b>Когда оправдан:</b> SaaS-продукты, веб-сервисы, команды с настроенным CI/CD, где деплой происходит после каждого мёрж в main. Простота модели снижает когнитивную нагрузку: все знают один набор правил.</p><p><b>Ограничение:</b> отсутствует встроенная концепция «релиза» и «staging». Если нужно поддерживать несколько версий одновременно — GitHub Flow не покрывает этот кейс без дополнительных договорённостей.</p><h2>Trunk-Based Development: всё в main, feature flags в помощь</h2><p>Trunk-Based Development (TBD) доводит идею короткоживущих веток до предела — разработчики интегрируют изменения напрямую в trunk несколько раз в день. Модель существует с 1990-х и вдохновила упрощённые подходы вроде GitHub Flow. Если используются ветки — они живут максимум 1–2 дня и сливаются без церемоний.</p><p>Незавершённый код скрывается за <b>feature flags</b>: функция есть в коде, но включается только для нужной аудитории. Это позволяет постоянно интегрировать изменения, не ломая прод. Системы вроде LaunchDarkly, Unleash или простейший конфиг-файл — стандартный инструментарий TBD-команд.</p><p><b>Когда оправдан:</b> зрелые команды с высоким покрытием тестами, быстрым CI (&lt; 10 минут), культурой маленьких атомарных коммитов. Google, Facebook, Amazon деплоят по этой модели тысячи раз в день. По данным DORA (State of DevOps 2018), элитные DevOps-команды деплоят в 46 раз чаще, чем команды с низкой зрелостью процессов.</p><p><b>Требования:</b> без надёжного CI/CD, автотестов и feature flags TBD превращается в хаос. Не пробуйте этот подход, если CI занимает больше 20 минут или нет хорошего тестового покрытия — нет универсального порога, но без него TBD рискован.</p><h2>GitLab Flow: среднее между двух крайностей</h2><p>GitLab Flow решает главный пробел GitHub Flow — отсутствие environment-веток. Концепция: main — это то, что разработано; staging — что протестировано; production — что в проде.</p><p>Фичи разрабатываются в ветках, сливаются в main, затем промоутируются вниз по цепочке окружений. Подход близок к реальности большинства команд: есть staging для QA, есть production для пользователей.</p><p><b>Когда оправдан:</b> команды, которым нужен staging/QA-процесс перед релизом, но сложность Git Flow избыточна. Хорошо сочетается с GitLab CI/CD и авто-деплоем по веткам.</p><h2>Таблица сравнения</h2><p></p>КритерийGit FlowGitHub FlowTrunk-BasedGitLab FlowРазмер командыСредние и крупныеЛюбойСредние+ЛюбойРелизный циклНедели — месяцыЕжедневноНесколько раз в деньДни — неделиСложность настройкиВысокаяНизкаяСредняяСредняяТребования к CI/CDЖелательноОбязательноКритичноОбязательноFeature flagsНе нужныОпциональноОбязательноОпциональноПоддержка нескольких версийДаНетНетЧастично<p></p><h2>Как выбрать: практические рекомендации</h2><p><b>Начните с GitHub Flow</b> — это разумный дефолт для большинства команд. Простые правила, понятный процесс PR/review, легко объяснить новичку. Если вы только выстраиваете процессы — это ваш выбор.</p><p><b>Переходите на Trunk-Based Development</b>, когда: CI стабильно проходит за &lt; 10 минут, команда привыкла к маленьким коммитам, есть инфраструктура для feature flags. Не форсируйте переход — команды, прыгнувшие в TBD без готовности, возвращаются обратно через месяц.</p><p><b>Выбирайте Git Flow</b> только если у вас длинные релизные циклы с обязательной сертификацией, поддержка нескольких мажорных версий одновременно (например, мобильное приложение с 1.x и 2.x у разных клиентов), или регуляторные требования к freeze-периодам.</p><p><b>Помните:</b> workflow — это договорённость внутри команды. Лучший workflow — тот, который все понимают и соблюдают. Формализованный Git Flow, который никто не соблюдает, хуже неформального «коммитим в main аккуратно». Также полезно настроить <a href="https://tproger.ru/articles/git-hooks-avtomatizaciya-proverok-pered-kommitom-i-puwem">Git hooks</a> для автоматической проверки соблюдения правил — linting, тесты, формат коммит-сообщений.</p><p>Git workflow — не религия. GitHub Flow подходит большинству команд прямо сейчас: он прост, понятен и хорошо масштабируется с CI/CD. Trunk-Based Development — следующий уровень для команд, которые хотят деплоить несколько раз в день и готовы инвестировать в инфраструктуру. Git Flow остаётся правильным выбором там, где он исторически появился — в продуктах с длинными релизными циклами. Выбирайте инструмент под задачу, а не под моду.</p>]]></content:encoded>
    </item>
    <item>
      <title>Git hooks: автоматизация проверок перед коммитом и пушем</title>
      <link>https://tproger.ru/articles/git-hooks-avtomatizaciya-proverok-pered-kommitom-i-puwem</link>
      <comments>https://tproger.ru/articles/git-hooks-avtomatizaciya-proverok-pered-kommitom-i-puwem?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/git-hooks-avtomatizaciya-proverok-pered-kommitom-i-puwem</guid>
      <description><![CDATA[<p>Разбираем Git hooks: pre-commit, commit-msg, pre-push — как настроить и автоматизировать проверки кода с помощью Husky, pre-commit framework и lefthook.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/git-hooks-avtomatizaciya-proverok-pered-kommitom-i-puwem">Git hooks: автоматизация проверок перед коммитом и пушем</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Apr 2026 15:24:59 GMT</pubDate>
      <content:encoded><![CDATA[<p>Вы когда-нибудь отправляли коммит с опечаткой в сообщении — или пушили сырой код, который ломал CI? Git hooks позволяют этого избежать: это скрипты, которые автоматически запускаются при определённых событиях в Git. Настроил один раз — и линтер, проверка формата, тесты выполняются сами, без участия разработчика.</p><p>В этой статье разберём клиентские и серверные хуки, напишем реальные bash-скрипты и сравним инструменты для управления хуками в команде: Husky, pre-commit framework и lefthook.</p><p>— Git hooks — скрипты в .git/hooks/, выполняемые при событиях Git (коммит, пуш, мерж)</p><p>— Клиентские хуки: pre-commit, commit-msg, pre-push и другие — запускаются на машине разработчика</p><p>— Серверные хуки: pre-receive, update, post-receive — контролируют пуши на сервере</p><p>— Husky, pre-commit framework и lefthook упрощают управление хуками в команде</p><p>— Хуки — это локальная автоматизация; CI/CD — серверная: они дополняют друг друга</p><p>Эта статья — часть нашего <a href="https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor">полного путеводителя по Git</a>. Там — весь маршрут: от первого коммита до продвинутых workflow.</p><h2>Что такое Git hooks</h2><p>Git hooks — это скрипты, которые Git запускает автоматически при определённых событиях: перед созданием коммита, после пуша, при мерже. Они живут в директории .git/hooks/ вашего репозитория.</p><p>По умолчанию там лежат примеры с расширением .sample — они неактивны. Чтобы активировать хук, достаточно убрать расширение и сделать файл исполняемым:</p><p>Скрипт может быть написан на любом языке: bash, Python, Ruby, Node.js — лишь бы интерпретатор был доступен в системе. Хук завершается с кодом 0 — операция продолжается; с ненулевым — Git прерывает её.</p><h2>Клиентские хуки</h2><p>Клиентские хуки выполняются на машине разработчика. Они не копируются при клонировании репозитория — каждый разработчик настраивает их сам (или через инструменты вроде Husky).</p><ul><li><b>pre-commit</b> — запускается до того, как Git создаст коммит. Здесь запускают линтеры, форматтеры, статический анализ. Если хук вернул ненулевой код — коммит не создаётся.</li><li><b>prepare-commit-msg</b> — запускается после создания сообщения коммита по умолчанию, но до его открытия в редакторе. Используется для автоматического добавления номера задачи из названия ветки.</li><li><b>commit-msg</b> — получает путь к файлу с сообщением коммита. Здесь проверяют, соответствует ли сообщение формату (например, Conventional Commits).</li><li><b>post-commit</b> — запускается после создания коммита. Используется для уведомлений; не влияет на сам коммит.</li><li><b>pre-push</b> — запускается перед git push. Здесь запускают тесты или запрещают пуш в защищённые ветки.</li><li><b>post-checkout</b> — вызывается после git checkout, git switch и git clone. Удобен для автоматической установки зависимостей после смены ветки.</li></ul><h2>Серверные хуки</h2><p>Серверные хуки выполняются на стороне Git-сервера (GitLab, Gitea, собственный сервер). Они позволяют централизованно контролировать все пуши — независимо от настроек на машинах разработчиков.</p><ul><li><b>pre-receive</b> — вызывается при получении пуша, до обновления веток. Может отклонить весь пуш целиком: проверяет права, политику коммитов, размер файлов.</li><li><b>update</b> — аналог pre-receive, но вызывается отдельно для каждой обновляемой ветки. Позволяет разрешить пуш в одни ветки и запретить в другие.</li><li><b>post-receive</b> — запускается после успешного пуша. Используется для уведомлений, триггеров деплоя, синхронизации с внешними системами.</li></ul><h2>Практические примеры</h2><p><b>pre-commit: запуск линтера перед коммитом</b></p><p>Хук проверяет только те файлы, которые добавлены в индекс. Это ускоряет проверку в больших проектах:</p><p><b>commit-msg: проверка формата сообщения</b></p><p>Хук проверяет, соответствует ли сообщение коммита формату Conventional Commits (feat: ..., fix: ..., docs: ... и т. д.):</p><p><b>pre-push: запрет пуша в main/master</b></p><p>Хук предотвращает случайный прямой пуш в защищённые ветки:</p><h2>Инструменты: Husky, pre-commit framework, lefthook</h2><p>Проблема «голых» хуков в том, что .git/hooks/ не попадает в репозиторий. Каждый разработчик должен настраивать их вручную. Инструменты решают эту проблему — хуки версионируются вместе с кодом и устанавливаются автоматически.</p><p><b>Husky</b> — самый популярный выбор для JavaScript-проектов. Хуки описываются в файлах директории .husky/ и устанавливаются через npm install. Интегрируется с lint-staged для запуска проверок только на изменённых файлах.</p><p><b>pre-commit framework</b> — мощный инструмент для Python-проектов (и не только). Хуки описываются в .pre-commit-config.yaml. Поддерживает большую экосистему готовых хуков — для Python, Go, Terraform, Docker и других технологий.</p><p><b>Lefthook</b> — быстрый инструмент на Go, работает в любом проекте независимо от языка. Конфигурация в lefthook.yml. Поддерживает параллельный запуск хуков, что заметно ускоряет проверку в монорепозиториях.</p><p>Краткое сравнение инструментов:</p><ul><li><b>Husky</b> — лучший выбор для Node.js/фронтенд-проектов. Глубокая интеграция с npm-экосистемой.</li><li><b>pre-commit framework</b> — богатая экосистема готовых хуков, идеален для Python и мультиязычных проектов.</li><li><b>lefthook</b> — самый быстрый, не зависит от языка, хорошо работает в монорепозиториях с параллельными задачами.</li></ul><h2>Хуки и CI/CD: дополняют, а не заменяют</h2><p>Git hooks и CI/CD решают одну задачу — автоматическую проверку кода — но на разных уровнях. Хуки работают локально, до отправки кода на сервер. Это быстрая первая линия обороны: разработчик получает обратную связь за секунды, не дожидаясь очереди в CI.</p><p>CI/CD — это серверная автоматизация: она запускается независимо от хуков и не может быть отключена разработчиком. CI выполняет более тяжёлые проверки: интеграционные тесты, сборку Docker-образов, деплой. О том, как выстроить полный пайплайн, читайте в <a href="https://tproger.ru/articles/roadmap-devops-inzhenera-v-2026-godu--chto-uchit-i-v-kakom-poryadke">roadmap DevOps-инженера</a>.</p><p>Правило: хуки проверяют то, что можно проверить быстро (секунды) — линт, форматирование, формат сообщения. CI проверяет то, что требует инфраструктуры — тесты с базой данных, e2e, performance benchmarks. Дублировать медленные проверки в хуках не стоит — разработчики будут обходить их через git commit --no-verify.</p><p>Git hooks — мощный инструмент, который превращает локальную разработку в управляемый процесс. Пять минут на настройку pre-commit и commit-msg экономят часы ревью в будущем. Начните с одного хука, убедитесь, что он не замедляет работу, и постепенно добавляйте остальные. Подробнее о том, как hooks вписываются в общий рабочий процесс с ветками и пулл-реквестами, читайте в статье про <a href="https://tproger.ru/articles/git-flow-github-flow-i-trunk-based-development-kakoj-workflow">Git Flow, GitHub Flow и Trunk-Based</a> разработку.</p>]]></content:encoded>
    </item>
    <item>
      <title>Git stash: как сохранить и восстановить незакоммиченные изменения</title>
      <link>https://tproger.ru/articles/git-stash-kak-sohranit-i-vosstanovit-nezakommichennye-izmeneni</link>
      <comments>https://tproger.ru/articles/git-stash-kak-sohranit-i-vosstanovit-nezakommichennye-izmeneni?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/git-stash-kak-sohranit-i-vosstanovit-nezakommichennye-izmeneni</guid>
      <description><![CDATA[<p>Узнайте, как git stash помогает сохранить незакоммиченные изменения, быстро переключиться на hotfix и вернуться к работе — с примерами всех ключевых команд.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/git-stash-kak-sohranit-i-vosstanovit-nezakommichennye-izmeneni">Git stash: как сохранить и восстановить незакоммиченные изменения</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Apr 2026 15:21:56 GMT</pubDate>
      <content:encoded><![CDATA[<p>Представь: ты в середине правки, и тебя просят срочно переключиться на другую ветку. Коммитить недоделанное — плохая идея. Откатывать изменения — потеря работы. Именно для таких случаев в Git есть git stash — временное хранилище незакоммиченных изменений.</p><p>Stash работает как стопка листков: кладёшь незавершённую работу «на полку», переключаешься на другую задачу, потом возвращаешься и достаёшь обратно. В этой статье разберём все основные команды — от базовых до продвинутых сценариев.</p><p>— git stash временно сохраняет незакоммиченные изменения и очищает рабочую директорию</p><p>— git stash pop применяет верхний stash и удаляет его; git stash apply применяет, но оставляет в стеке</p><p>— Флаг -u добавляет в stash неотслеживаемые файлы, флаг --keep-index оставляет staged-изменения нетронутыми</p><p>— При конфликте после pop stash не удаляется автоматически — нужно разрешить конфликты вручную</p><p>— git stash branch создаёт новую ветку прямо из stash — удобно для сложных случаев</p><p>Эта статья — часть нашего полного путеводителя по Git. Там — весь маршрут: от первого коммита до продвинутых workflow.</p><h2>Что такое git stash и зачем он нужен</h2><p>git stash сохраняет все изменения в рабочей директории (tracked-файлы) в специальный стек внутри репозитория и возвращает рабочую директорию к последнему коммиту. Это не коммит — изменения не попадают в историю. Это временная полка.</p><p>Stash хранится локально в .git/refs/stash и не отправляется при git push. Стек может содержать любое количество записей.</p><h2>Именованные stash: git stash push -m</h2><p>Без имени stash называется WIP on branch-name: hash message — не очень информативно. Флаг -m задаёт понятное описание:</p><p>Хорошее описание особенно важно, когда в стеке накапливается несколько записей. Через неделю «WIP on main: a3f2b1c» ничего не скажет — в отличие от конкретного сообщения.</p><h2>Просмотр: list и show</h2><p>Индексы в стеке работают как в массиве: stash@{0} — последний сохранённый, stash@{1} — предыдущий и так далее.</p><h2>Применение и удаление: pop, apply, drop, clear</h2><p>Ключевое различие между pop и apply: первый удаляет запись из стека после применения, второй — нет. Используй apply, если хочешь подстраховаться и оставить stash до полной проверки результата.</p><h2>Включить untracked файлы: git stash -u</h2><p>По умолчанию git stash сохраняет только отслеживаемые файлы (те, что уже есть в индексе). Новые файлы, которые ещё не добавлены через git add, остаются в рабочей директории.</p><p>Флаг -u (или --include-untracked) добавляет и их:</p><h2>Сохранить только unstaged: git stash --keep-index</h2><p>Иногда нужно убрать только рабочие (unstaged) изменения, оставив всё, что уже добавлено через git add. Флаг --keep-index делает именно это:</p><p>Удобно, когда готовишь коммит: добавил нужное в staged, а незакоммиченные черновики убрал временно — и коммитишь только то, что хотел.</p><h2>Конфликты при pop: что делать</h2><p>Если с момента сохранения stash основная ветка ушла вперёд и изменились те же строки, при git stash pop возникнут конфликты — точно так же, как при merge.</p><p>Важно: при конфликте pop не удаляет stash из стека автоматически. Это защита от потери данных — решай конфликты спокойно.</p><p>Если конфликты слишком сложные — лучше использовать git stash branch, о котором расскажем ниже.</p><h2>Практический сценарий: hotfix без потери текущей работы</h2><p>Классическая ситуация: ты разрабатываешь новую фичу, и приходит сообщение «упал прод, нужен срочный фикс». Вот как это решается с git stash:</p><p>Весь процесс занимает меньше минуты. Незакоммиченная работа сохранена, история не засорена недоделанными коммитами.</p><h2>git stash branch: создать ветку из stash</h2><p>Бывает, что изменений в stash накопилось так много, что применить их поверх текущей ветки без конфликтов не получится. Команда git stash branch решает это элегантно: она создаёт новую ветку с того коммита, где был сделан stash, и применяет его туда без конфликтов.</p><p>После успешного применения stash удаляется автоматически. Это лучший вариант, когда работа в stash выросла в самостоятельную задачу или когда конфликты неизбежны.</p><p>Если тебе нужно не просто отложить изменения, а откатить уже сделанные коммиты, читай как откатить коммит в Git — там разобраны git reset, git revert и когда что использовать.</p><p>git stash — один из самых полезных инструментов в ежедневной работе с Git. Он избавляет от необходимости делать «грязные» коммиты ради переключения контекста, позволяет быстро реагировать на срочные задачи и аккуратно управлять незавершённой работой. Освой эти команды, и переключение между задачами перестанет быть стрессом.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как откатить коммит в Git: reset, revert, checkout</title>
      <link>https://tproger.ru/articles/kak-otkatit-kommit-v-git-reset-revert-checkout</link>
      <comments>https://tproger.ru/articles/kak-otkatit-kommit-v-git-reset-revert-checkout?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-otkatit-kommit-v-git-reset-revert-checkout</guid>
      <description><![CDATA[<p>git revert, git reset и git restore: разбираем три способа откатить коммит в Git. Таблица режимов --soft/--mixed/--hard, сценарии и готовые примеры команд.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-otkatit-kommit-v-git-reset-revert-checkout">Как откатить коммит в Git: reset, revert, checkout</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Apr 2026 15:21:52 GMT</pubDate>
      <content:encoded><![CDATA[<p>Каждый разработчик рано или поздно делает коммит, который нужно отменить. Закоммитил не ту ветку, запушил секрет, сломал рабочий код — ситуации разные, но вопрос один: как это исправить? В Git есть три основных инструмента для отмены изменений: git revert, git reset и git restore. Разберём, когда использовать каждый из них и чем они отличаются.</p><p>— git revert создаёт новый коммит-отмену, безопасен после push в общую ветку</p><p>— git reset переносит указатель HEAD назад; бывает трёх видов: --soft, --mixed, --hard</p><p>— git restore / git checkout -- file отменяет изменения в рабочей директории или убирает файл из staging area</p><p>— Правило: если уже запушил — только revert; если локально — reset</p><h2>git revert: безопасная отмена после push</h2><p>git revert — самый безопасный способ отменить коммит. Он не переписывает историю, а создаёт новый коммит, который применяет обратные изменения. Именно поэтому revert подходит для публичных веток: коллеги, которые уже получили ваши изменения через pull, не столкнутся с конфликтами.</p><p>После выполнения команды Git откроет редактор для сообщения нового коммита — по умолчанию там будет что-то вроде Revert "Добавил новую фичу". Флаг --no-edit пропускает этот шаг и принимает сообщение автоматически.</p><p>Сценарий: вы запушили в main коммит с ошибкой, коллеги уже сделали pull. Использовать git reset здесь опасно — история разойдётся. Правильное решение: git revert HEAD и git push. Все получат отмену через обычный pull.</p><h2>git reset: три режима работы</h2><p>git reset перемещает указатель HEAD на указанный коммит, переписывая историю. Используйте только для локальных коммитов, которые ещё не запушены в общую ветку. Команда имеет три режима, которые отличаются тем, что происходит с индексом (staging area) и рабочей директорией.</p><ul><li><b>--soft</b> — история откатывается, но все изменения остаются в индексе (готовы к коммиту)</li><li><b>--mixed</b> (по умолчанию) — история откатывается, изменения возвращаются в рабочую директорию, но из индекса убираются</li><li><b>--hard</b> — история откатывается, все изменения удаляются и из индекса, и из рабочей директории</li></ul><p>Сравнение трёх режимов git reset:</p><ul><li><b>--soft:</b> история изменяется, индекс сохраняется, рабочая директория сохраняется — применять, когда нужно переформулировать коммит или объединить несколько коммитов в один</li><li><b>--mixed:</b> история изменяется, индекс очищается, рабочая директория сохраняется — применять, когда нужно перевыбрать файлы для коммита</li><li><b>--hard:</b> история изменяется, индекс очищается, рабочая директория очищается — применять, когда нужно полностью выбросить изменения и вернуться к чистому состоянию</li></ul><p>Практический пример: вы сделали три коммита с правками в одном файле и хотите отправить их как один. Используйте git reset --soft HEAD~3 — все три коммита исчезнут из истории, но изменения останутся в индексе. Остаётся сделать один финальный коммит.</p><h2>git restore и git checkout: отмена изменений в файлах</h2><p>Если нужно отменить изменения не в истории коммитов, а в конкретных файлах, используйте git restore (доступен с Git 2.23) или его предшественника git checkout -- file.</p><p>Сценарий: вы случайно добавили в git add файл с секретом .env. Перед коммитом выполните git restore --staged .env — файл останется на диске, но выйдет из индекса и не попадёт в коммит. Лучше сразу добавить его в .gitignore, чтобы не повторялось.</p><p>Если нужно вернуть файл к состоянию из определённого коммита, а не из HEAD, передайте хеш явно: git restore --source=a1b2c3d README.md. Это удобно, если файл менялся в нескольких коммитах и нужна конкретная версия.</p><h2>Три сценария и как их решать</h2><p><b>Сценарий 1: запушил не то в общую ветку.</b> Уже сделали git push, коллеги могли получить изменения. Единственное безопасное решение — git revert HEAD и повторный push. Переписывать историю через reset здесь нельзя.</p><p><b>Сценарий 2: сломал рабочую ветку локальными коммитами.</b> Изменения ещё не запушены. Используйте git reset --hard origin/main — ветка вернётся к состоянию на удалённом репозитории, все локальные коммиты и изменения исчезнут. Или git reset --mixed, если хотите сохранить файлы.</p><p><b>Сценарий 3: нужно убрать файл из последнего коммита.</b> Коммит ещё локальный. Сначала отмените коммит: git reset --soft HEAD~1. Потом уберите файл из индекса: git restore --staged secret.txt. Затем сделайте новый коммит без этого файла.</p><p>Подробнее о похожих ситуациях читайте в статье про <a href="https://tproger.ru/translations/most-common-git-screwupsquestions-and-solutions">типичные ошибки Git</a> — там разобраны десятки реальных кейсов с решениями.</p><h2>Что выбрать: reset, revert или restore</h2><p>Правило трёх вопросов, которое поможет выбрать инструмент:</p><ul><li><b>Изменения уже запушены в общую ветку?</b> — только git revert</li><li><b>Нужно отменить коммиты локально?</b> — git reset (выберите режим по необходимости)</li><li><b>Нужно отменить изменения в файлах (не коммиты)?</b> — git restore</li></ul><ul><li><b>git revert</b> — создаёт новый коммит-отмену, не переписывает историю, безопасен после push; подходит для общих веток</li><li><b>git reset</b> — переносит HEAD назад, переписывает историю, только для локальных изменений; подходит для личных веток и правки последних коммитов</li><li><b>git restore</b> — отменяет изменения в файлах или убирает из staging, не трогает историю коммитов; подходит для отмены несохранённых изменений</li></ul><p>Запомните простое правило: если коммит уже попал в общую ветку — только git revert. Если ещё локальный — можно использовать git reset с нужным флагом. А git restore — для быстрой отмены изменений в файлах до коммита. Эти три инструмента покрывают 95% ситуаций, с которыми сталкиваются разработчики в повседневной работе.</p>]]></content:encoded>
    </item>
    <item>
      <title>Git rebase vs merge: когда что использовать и в чём разница</title>
      <link>https://tproger.ru/articles/git-rebase-vs-merge-kogda-chto-ispolzovat-i-v-chyom-raznica</link>
      <comments>https://tproger.ru/articles/git-rebase-vs-merge-kogda-chto-ispolzovat-i-v-chyom-raznica?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/git-rebase-vs-merge-kogda-chto-ispolzovat-i-v-chyom-raznica</guid>
      <description><![CDATA[<p>Разбираем git merge и git rebase: как работает каждая команда, когда использовать rebase, а когда merge, и почему нарушение золотого правила ломает историю.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/git-rebase-vs-merge-kogda-chto-ispolzovat-i-v-chyom-raznica">Git rebase vs merge: когда что использовать и в чём разница</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Apr 2026 15:21:40 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы работаете с Git в команде, рано или поздно встаёт вопрос: как объединить ветки — через git merge или через git rebase? Оба инструмента решают одну задачу — интегрируют изменения из одной ветки в другую, — но делают это совершенно по-разному. Неправильный выбор может превратить историю репозитория в хаос или создать проблемы для всей команды.</p><p>В этой статье разберём, как работает каждая команда, когда что применять и почему нарушение золотого правила rebase ведёт к конфликтам у коллег. Статья подойдёт разработчикам, которые уже знакомы с базовыми командами Git и хотят разобраться с ветвлением и историей коммитов.</p><p>— <b>merge</b> создаёт merge-коммит и сохраняет полную историю веток — когда и откуда пришли изменения.</p><p>— <b>rebase</b> переносит коммиты на новую базу и создаёт линейную историю без лишних merge-коммитов.</p><p>— Золотое правило: <b>никогда не ребейсить публичные ветки</b>, которые уже запушены и используются другими.</p><p>— feature-ветки перед слиянием — rebase; main/develop при получении чужих изменений — merge или pull --rebase.</p><p>— interactive rebase (git rebase -i) позволяет склеить, переименовать и отредактировать коммиты до публикации.</p><p>Также полезно изучить <a href="https://tproger.ru/translations/git-tips-and-tricks">полезные команды Git</a> — там собраны практические приёмы на каждый день.</p><h2>Как работает git merge</h2><p>git merge объединяет две ветки, создавая новый коммит — <b>merge-коммит</b>. Этот коммит имеет двух родителей: последний коммит текущей ветки и последний коммит ветки, которую вы вливаете. История полностью сохраняется: видно, когда ветка была создана, что в ней менялось, когда слита обратно.</p><p>Merge безопасен для публичных веток: он только добавляет новый коммит, не меняя существующие. Коллеги, которые уже склонировали репозиторий, без проблем сделают git pull и получат обновлённую историю.</p><p>Минус — при активной разработке история быстро засоряется merge-коммитами. Если в команде 10 человек и у каждого по несколько веток, граф становится нечитаемым.</p><h2>Как работает git rebase</h2><p>git rebase переносит коммиты текущей ветки на новую базу — то есть «перекладывает» их поверх другой ветки. При этом Git создаёт <b>новые коммиты</b> с теми же изменениями, но другими хешами. Результат — линейная история без лишних merge-коммитов.</p><p>Обратите внимание: D и E превращаются в D' и E' — это другие коммиты. Именно поэтому rebase опасен для ветки, которую уже видели другие разработчики: у них в локальных репозиториях останутся старые D и E, а в origin появятся новые D' и E'. При следующем git pull возникнет путаница и конфликты.</p><h2>Interactive rebase: squash, fixup, reword</h2><p>Флаг -i (interactive) открывает редактор со списком коммитов, которые можно переупорядочить и изменить перед публикацией. Это мощный инструмент для «уборки» истории feature-ветки до создания pull request.</p><p>Откроется список вида:</p><p>Команды, доступные в interactive rebase:</p><ul><li>squash (или s) — склеить коммит с предыдущим, объединить сообщения</li><li>fixup (или f) — склеить с предыдущим, выбросить сообщение этого коммита</li><li>reword (или r) — изменить только сообщение коммита</li><li>edit (или e) — остановиться на коммите и внести изменения в файлы</li><li>drop (или d) — удалить коммит</li></ul><p>Типичный сценарий: перед созданием PR склеить несколько черновых коммитов («WIP», «ещё правки», «исправить тест») в один чистый коммит с понятным сообщением. Команда увидит осмысленную историю, а не рабочий дневник.</p><h2>Когда что использовать</h2><p>Нет универсального ответа — выбор зависит от контекста и договорённостей в команде. Вот практические ориентиры.</p><h3>feature-ветка → используйте rebase</h3><p>Если вы работаете над личной feature-веткой, которую ещё не публиковали (или публиковали, но работаете в одиночку), — обновляйтесь через rebase:</p><p>Так ваши коммиты окажутся поверх актуального main, и PR будет применяться чисто, без merge-коммита. История останется линейной.</p><h3>Слияние в main → используйте merge</h3><p>Когда feature-ветка проверена и одобрена, её сливают в основную ветку через merge. В большинстве команд это делается через pull request, и CI автоматически создаёт merge-коммит. Это нормально: merge-коммит в main фиксирует факт слияния и сохраняет связь с веткой.</p><h3>Общая ветка → никогда rebase</h3><p>Если над веткой работают несколько разработчиков, git rebase категорически нельзя использовать. Rebase переписывает хеши — и у коллег возникнет рассинхронизация. При следующем git pull Git увидит два «параллельных» набора коммитов с одинаковыми изменениями, и придётся вручную разбираться с конфликтами.</p><h2>Золотое правило rebase</h2><blockquote>Никогда не делайте rebase ветки, которая уже запушена в удалённый репозиторий и используется другими разработчиками.</blockquote><p>Это правило звучит просто, но регулярно нарушается. Сценарий: вы запушили feature-ветку, открыли PR, получили ревью — и решили «подчистить» историю через git rebase -i. После этого придётся делать git push --force. Если коллега уже склонировал вашу ветку — у него сломается история.</p><p>Исключение: git push --force-with-lease — более безопасная версия force push, которая откажет, если кто-то успел запушить в ту же ветку. Но лучше договориться в команде заранее: нужна ли вам линейная история или достаточно merge-коммитов.</p><h2>Сравнение: merge vs rebase</h2><ul><li><b>История:</b> merge — нелинейная с merge-коммитами; rebase — линейная, как будто ветки не было</li><li><b>Безопасность для команды:</b> merge — всегда безопасен; rebase — только на локальных или личных ветках</li><li><b>Трассировка:</b> merge — видно, когда и откуда пришли изменения; rebase — история «переписана», оригинальные хеши утеряны</li><li><b>Конфликты:</b> merge — разрешаются один раз; rebase — могут появляться на каждом переносимом коммите</li><li><b>Читаемость:</b> merge — граф коммитов быстро загромождается; rebase — чистая линейная история</li><li><b>Откат:</b> merge — git revert по merge-коммиту; rebase — откатить сложнее, так как хеши изменились</li></ul><h2>Заключение</h2><p>Выбор между merge и rebase — это не вопрос «что лучше», а вопрос «что нужно здесь». Merge сохраняет полную картину истории и безопасен для общих веток. Rebase даёт чистую линейную историю и идеален для подготовки feature-веток перед слиянием. Главное правило: не переписывайте то, что уже видели другие. Договоритесь о конвенции с командой — и придерживайтесь её.</p>]]></content:encoded>
    </item>
    <item>
      <title>Франкенштейн в медицине: как я скрестил ViT и ruGPT-3, чтобы научить ИИ читать рентген на русском</title>
      <link>https://tproger.ru/articles/frankenwtejn-v-medicine--kak-ya-skrestil-vit-i-rugpt-3--chtoby-nau</link>
      <comments>https://tproger.ru/articles/frankenwtejn-v-medicine--kak-ya-skrestil-vit-i-rugpt-3--chtoby-nau?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[максим митин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/frankenwtejn-v-medicine--kak-ya-skrestil-vit-i-rugpt-3--chtoby-nau</guid>
      <description><![CDATA[<p>Практический кейс: создание русскоязычной мультимодальной нейросети (Vision-Language) для анализа рентгеновских снимков. Скрещиваем ViT и ruGPT-3, решаем проблемы с датасетами на Kaggle и выкатываем ИИ в продакшн на Hugging Face. Открытый код на Python.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/frankenwtejn-v-medicine--kak-ya-skrestil-vit-i-rugpt-3--chtoby-nau">Франкенштейн в медицине: как я скрестил ViT и ruGPT-3, чтобы научить ИИ читать рентген на русском</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[NVIDIA]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Сбер]]></category>
      <category><![CDATA[Машин]]></category>
      <category><![CDATA[GPU]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 05 Apr 2026 06:30:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Сейчас из каждого утюга рассказывают про мультимодальные нейросети: GPT-4o смотрит через камеру, Gemini анализирует видео. В медицине тоже есть крутые открытые ИИ-модели для анализа снимков (например, на базе датасетов MIMIC-CXR), но у них всех есть один фатальный недостаток для нашего рынка — они говорят исключительно на английском.</p><p>Мне стало интересно: а можно ли на бесплатных мощностях, буквально "на коленке", собрать русскоязычного ИИ-рентгенолога? Спойлер: можно. В этой статье расскажу, как я скрестил Vision Transformer от Google с ruGPT-3 от Сбера, как боролся с датасетами на Kaggle и что из этого вышло. В конце — ссылки на GitHub и рабочее демо.</p><h2>Архитектура: как пришить глаза к мозгу</h2><p>Чтобы нейросеть могла посмотреть на снимок и написать текст, нужна архитектура Vision-Language Model. Обучать такого монстра с нуля у меня не было ни ресурсов, ни желания. Поэтому я пошел по пути Hugging Face VisionEncoderDecoderModel.</p><p>Идея проста как кирпич:</p><ol><li>Энкодер (Глаза): Берем предобученный google/vit-base-patch16-224-in21k. Он отлично дробит картинку на патчи и извлекает визуальные фичи (понимает, где ребра, а где легкие).</li><li>Декодер (Язык): Берем ai-forever/rugpt3small_based_on_gpt2. У нее нет глаз, она умеет только генерировать текст.</li></ol><p>Чтобы их сшить, пришлось немного "взломать" конфиг ruGPT-3, принудительно сказав ей: «Теперь ты декодер, и у тебя есть слои кросс-внимания» (is_decoder=True, add_cross_attention=True). Hugging Face заботливо создал новые пустые веса между двумя моделями. Именно эти связи мне и предстояло обучить.</p><h2>Data Engineering: боль, страдания и Kaggle</h2><p>Найти 7-10 тысяч рентгеновских снимков с подробными заключениями на русском языке в открытом доступе — задача нереальная.</p><p>Поэтому я взял открытый американский датасет Indiana University Chest X-Ray (IU X-Ray). Там есть картинки и тексты от американских врачей.</p><p>Прямо на Kaggle я поднял пайплайн машинного перевода на базе Helsinki-NLP/opus-mt-en-ru. Закинул тексты в GPU батчами по 32 штуки и за 10 минут перевел более 7000 медицинских заключений на вполне сносный русский медицинский язык.</p><p>Но тут платформа подкинула сюрприз: Kaggle прячет часть файлов в виртуальной файловой системе (снимков 7000, а стандартный скрипт видел только 4). Пришлось писать суровый маппинг с глубоким сканированием (os.walk), отрезать расширения и жестко связывать ID в CSV с реальными путями на диске.</p><h2>Обучение: выжимаем все соки из бесплатных T4</h2><p>Обучение проходило на Kaggle (2x NVIDIA T4). Чтобы модель не умерла от нехватки памяти (OOM), а сессия не отвалилась по тайм-ауту, пришлось шаманить:</p><ul><li>Включил Mixed Precision (fp16) — ускорило обучение в 2 раза.</li><li>Настроил Gradient Accumulation — размер батча на видеокарту был всего 4, но виртуально мы накапливали до 16.</li><li>Столкнулся с тем, что Seq2SeqTrainer крашится при попытке сохранить промежуточный чекпоинт мультимодального "франкенштейна". Решение? Выключить промежуточные сохранения (save_strategy="epoch") и молиться, чтобы Kaggle не завис. (Кстати, спасает JS-скрипт в консоли браузера, делающий клик раз в 60 секунд).</li></ul><p>На 15 эпох ушло около 2.5 часов.</p><h2>Что получилось в итоге? (Потрогать руками)</h2><p>Получилась нейросеть, которая реально понимает, что изображено на рентгене, и сыпет терминами вроде «кальцифицированная гранулема» или «легочная васкулярность». Да, иногда она "галлюцинирует" (датасет в 7к снимков — это капля в море для ML), но базовые вещи вроде чистых легких или пневмоторакса сечет неплохо.</p><p>Я завернул модель в Gradio и выложил на Hugging Face Spaces. Можно зайти с телефона или ПК, загрузить любой снимок рентгена из гугла и посмотреть, что она выдаст.</p><p>👉 Потыкать лайв-демо тут: <a rel="noopener noreferrer" href="https://www.google.com/url?sa=E&amp;q=https%3A%2F%2Fhuggingface.co%2Fspaces%2Flivadies%2FAI-Radiologist-RU">Hugging Face Space</a></p><p>👉 Весь код, пайплайны и веса тут: <a rel="noopener noreferrer" href="https://www.google.com/url?sa=E&amp;q=https%3A%2F%2Fgithub.com%2Flivadies-collab%2FMultimodal-XRay-Analyzer-RU">GitHub Репозиторий</a></p><p>Буду рад, если кому-то этот код сэкономит время при создании своих мультимодальных сеток. Залетайте в репу, ставьте звездочки, форкайте. Если есть идеи, как улучшить датасет (может, прогнать переводы через LLM для чистки медицинского сленга) — пишите в комменты!</p><p>(Дисклеймер: модель обучена в исследовательских целях за вечер. Не суйте ей свои снимки вместо похода к реальному врачу)</p>]]></content:encoded>
    </item>
    <item>
      <title>Что такое GitOps простыми словами: Git как источник истины для деплоя</title>
      <link>https://tproger.ru/articles/chto-takoe-gitops-prostymi-slovami--git-kak-istochnik-istiny-dlya-d</link>
      <comments>https://tproger.ru/articles/chto-takoe-gitops-prostymi-slovami--git-kak-istochnik-istiny-dlya-d?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/chto-takoe-gitops-prostymi-slovami--git-kak-istochnik-istiny-dlya-d</guid>
      <description><![CDATA[<p>Что такое GitOps простыми словами: как деплоить через Git, а не руками, чем GitOps отличается от CI/CD и когда его уже пора внедрять в Kubernetes.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/chto-takoe-gitops-prostymi-slovami--git-kak-istochnik-istiny-dlya-d">Что такое GitOps простыми словами: Git как источник истины для деплоя</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 04 Apr 2026 04:56:46 GMT</pubDate>
      <content:encoded><![CDATA[<p>После <a href="https://tproger.ru/articles/chto-takoe-ci-cd--nepreryvnaya-integraciya-i-dostavka">CI/CD</a>, <a href="https://tproger.ru/articles/chto-takoe-kubernetes--orkestraciya-kontejnerov-prostymi-slovami">Kubernetes</a> и <a href="https://tproger.ru/articles/chto-takoe-helm-i-helm-charts--paketnyj-menedzher-dlya-kubernetes-p">Helm</a> почти у каждой команды появляется одна и та же боль: выкладка вроде бы уже автоматизирована, но финальное состояние кластера всё равно зависит от ручных действий. Кто-то меняет манифест прямо в production, кто-то запускает kubectl apply с ноутбука, кто-то правит values-файлы мимо review. В итоге Git хранит одну правду, а кластер живёт по другой.</p><p><b>GitOps</b> появился как ответ именно на эту проблему. Идея простая: желаемое состояние приложения и инфраструктуры хранится в Git, а специальный контроллер сам приводит кластер к этому состоянию. Разработчик не «деплоит руками» в Kubernetes, а меняет конфигурацию в репозитории, после чего система синхронизирует окружение с Git.</p><p>GitOps — это способ управлять конфигурацией и деплоем через Git, а не через ручные действия в кластере.</p><p>Он не заменяет CI/CD: CI собирает артефакт, а GitOps следит, чтобы среда реально пришла к состоянию из репозитория.</p><p>На практике GitOps чаще всего встречается в Kubernetes-связке с Argo CD или Flux CD, Helm и Kustomize.</p><p>Главная ценность GitOps — прозрачная история изменений, воспроизводимость и меньше ручных правок в production.</p><p>Если у команды ещё нет Docker, CI/CD, review-процесса и понятной структуры конфигурации, GitOps внедрять рано.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-04-04/d652f054-eb4f-450d-82ec-666f83915a6d.webp" alt="Схема GitOps-цикла: коммит, merge, GitOps-контроллер, синхронизация кластера и drift." /><figcaption>Упрощённый GitOps-поток: команда меняет конфигурацию в Git, а контроллер приводит кластер к желаемому состоянию.</figcaption></figure><p>Если у вас ещё плавают базовые термины, лучше идти по цепочке: <a href="https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih">Git и GitHub</a>, <a href="https://tproger.ru/articles/chto-takoe-ci-cd--nepreryvnaya-integraciya-i-dostavka">CI/CD</a>, <a href="https://tproger.ru/articles/chto-takoe-kubernetes--orkestraciya-kontejnerov-prostymi-slovami">Kubernetes</a> и <a href="https://tproger.ru/articles/chto-takoe-helm-i-helm-charts--paketnyj-menedzher-dlya-kubernetes-p">Helm</a>. Но если кластер у вас уже есть, а релизы всё ещё зависят от ручного kubectl, значит вы уже упёрлись в ту самую проблему, которую GitOps решает.</p><h2>Что такое GitOps и зачем он нужен</h2><p>GitOps — это способ управлять выкладкой и конфигурацией через Git. Манифесты, Helm values, Kustomize-оверлеи и другие декларативные описания лежат в репозитории, а изменения проходят через обычный процесс: commit, pull request, review и merge. После этого контроллер в кластере приводит среду к состоянию из Git.</p><p>Если говорить языком OpenGitOps и <a href="https://argo-cd.readthedocs.io/en/latest/">Argo CD</a>, у вас есть desired state в Git и live state в кластере. Когда они расходятся, система показывает drift и может синхронизировать окружение обратно к версии, зафиксированной в репозитории.</p><ul><li>Git хранит не только код, но и манифесты, Helm chart-ы, Kustomize-конфигурации и параметры окружений.</li><li>Изменения проходят через review и историю коммитов, а не через ручной доступ к production.</li><li>Откат для декларативной конфигурации часто сводится к возврату предыдущего commit или merge request.</li><li>Состояние среды становится проверяемым: то, что описано в репозитории, должно совпадать с тем, что реально запущено.</li></ul><p>Если совсем коротко: CI/CD отвечает на вопрос «как собрать и доставить новую версию», а GitOps — на вопрос «как гарантировать, что среда реально живёт по описанию из Git».</p><h2>Как работает GitOps на практике</h2><p>Основная механика GitOps крутится вокруг трёх сущностей: репозиторий с желаемым состоянием, контроллер в кластере и цикл синхронизации. Разработчик меняет не сам кластер, а конфигурацию в Git. Контроллер читает репозиторий, сравнивает его с реальным состоянием и приводит окружение к нужной версии.</p><h3>Git как источник истины</h3><p>Проще всего думать так: Git хранит не “примерную конфигурацию”, а целевое описание среды. Если сервис должен работать с двумя репликами, конкретным образом и определёнными ingress-правилами, именно репозиторий считается источником этой правды.</p><p>Это не единственно правильная структура, но принцип один и тот же: production описан в Git, а не существует только в голове дежурного инженера или в shell history.</p><h3>Контроллер и reconciliation loop</h3><p>В кластере обычно работает GitOps-контроллер или стек контроллеров, например Argo CD или Flux CD. Он регулярно сравнивает репозиторий с текущим состоянием среды. Если что-то не совпадает, приложение помечается как рассинхронизированное, а дальше система либо показывает diff, либо сама подтягивает кластер к desired state из Git.</p><h3>Почему это лучше ручного kubectl</h3><p>Ручной деплой ломается не только из-за ошибок в YAML. Он ломается из-за неявности: непонятно, кто и когда поменял кластер, почему staging отличается от production и какой набор команд вообще был выполнен. GitOps убирает эту “устную традицию”: история изменений живёт в commit и pull request, а не в чьей-то памяти или shell history.</p><p>Самый понятный сценарий выглядит так: CI собрал образ api:1.4.2, команда поменяла тег в values-prod.yaml через pull request, после merge Argo CD подтянул новую конфигурацию в кластер. Если кто-то потом руками вернёт старый тег или изменит число реплик прямо в live-среде, контроллер увидит drift и покажет, что кластер разошёлся с Git.</p><h2>Чем GitOps отличается от CI/CD</h2><p>GitOps часто путают с CI/CD, потому что обе темы связаны с доставкой изменений. Но зона ответственности у них разная: CI/CD собирает и публикует артефакт, а GitOps отвечает за то, чтобы среда действительно пришла к конфигурации из Git.</p><ul><li><b>CI</b> проверяет код: тесты, линтеры, сборка, статический анализ.</li><li><b>CD</b> публикует артефакт: image, package, release или deployment-пакет.</li><li><b>GitOps</b> управляет desired state среды: манифестами, Helm values, Kustomize-оверлеями и другими конфигурациями.</li><li>В реальной цепочке они работают вместе: CI собрал образ, CD довёл его до registry, а GitOps синхронизировал кластер с новой конфигурацией из Git.</li></ul><p>Поэтому фраза «GitOps заменяет CI/CD» некорректна. Типовой сценарий такой: CI собрал образ api:1.4.2, команда обновила тег в values-prod.yaml через pull request, после merge Argo CD увидел diff и применил новый релиз в кластер. Пока этот последний шаг живёт вне Git, у вас есть CI/CD, но нет управляемого desired state.</p><h2>Какие инструменты чаще всего используют для GitOps</h2><p>GitOps — это не конкретный продукт, а подход. Но в Kubernetes-мире есть несколько типовых инструментов, которые чаще всего закрывают эту задачу.</p><ul><li><a href="https://tproger.ru/articles/razbiraem-argocd--avtomatizirovannyj-deploj-v-kubernetes">Argo CD</a> — удобный первый выбор, если нужен понятный UI, diff, sync-статусы и наглядная работа с приложениями в Kubernetes.</li><li><a href="https://fluxcd.io/">Flux CD</a> — GitOps-стек из нескольких контроллеров, который часто выбирают команды, предпочитающие максимально Git-centric и CRD-based подход.</li><li><a href="https://tproger.ru/articles/chto-takoe-helm-i-helm-charts--paketnyj-menedzher-dlya-kubernetes-p">Helm</a> — не GitOps-инструмент сам по себе, а упаковочный слой для релизов, с которым удобно работать GitOps-контроллеру.</li><li>Kustomize — способ описывать вариации конфигурации без шаблонов; часто используется там, где команда хочет хранить разные окружения рядом, но без Helm chart-ов.</li></ul><p>Для первого внедрения обычно не нужен сложный зоопарк инструментов. Достаточно одной понятной связки: например, Argo CD плюс Helm или Flux CD плюс Kustomize. Важнее не количество компонентов, а дисциплина: изменения в production идут только через Git.</p><h2>Где GitOps особенно полезен, а где его рано внедрять</h2><p>GitOps особенно хорошо раскрывается там, где уже есть несколько окружений, несколько сервисов и больше одного человека, который влияет на деплой. Как только конфигурация начинает жить отдельно от кода, а изменения попадают в кластер в обход review, GitOps перестаёт быть модным словом и становится способом вернуть контроль над средой.</p><ul><li>Уже пора: у вас есть Kubernetes, staging и production, несколько сервисов или несколько команд, а история изменений в кластере должна быть прозрачной.</li><li>Уже пора: релизы регулярно упираются в ручной kubectl, чат-инструкции или правки values-файлов мимо pull request.</li><li>Пока рано: если у вас ещё нет нормального <a href="https://tproger.ru/articles/chto-takoe-docker-prostymi-slovami--kontejnery--obrazy-i-docker-c">контейнерного</a> и <a href="https://tproger.ru/articles/chto-takoe-ci-cd--nepreryvnaya-integraciya-i-dostavka">CI/CD</a>-фундамента.</li><li>Пока рано: если команда пока не умеет поддерживать манифесты, Helm values и окружения в Git без хаоса и копипаста.</li></ul><p>GitOps не чинит плохую инженерную дисциплину автоматически. Если в репозитории бардак, нет review, chart-ы размножены копированием, а secrets живут где попало, контроллер начнёт очень последовательно раскатывать этот бардак по окружениям.</p><h2>Типичные ошибки при внедрении GitOps</h2><ol><li>Считать, что GitOps = Argo CD. Argo CD — только один из инструментов, а не весь подход целиком.</li><li>Пытаться внедрить GitOps до Docker, CI/CD и базовой дисциплины вокруг Git и review.</li><li>Хранить в Git хаотичную конфигурацию без структуры по окружениям, сервисам и зонам ответственности.</li><li>Смешивать сборку артефакта и управление состоянием среды в один непрозрачный pipeline.</li><li>Оставлять ручные hotfix-изменения в кластере без возврата их в репозиторий.</li><li>Думать, что GitOps отменяет мониторинг, rollback-план и нормальную эксплуатацию stateful-компонентов.</li></ol><p>Хороший тест на зрелость простой: после инцидента вы открываете Git и видите, какая конфигурация должна быть в production. Потом возвращаете кластер к этому состоянию без ручной магии. Но важно помнить границу: GitOps хорошо откатывает декларативные ресурсы и desired state, а миграции базы, данные и внешние зависимости всё равно требуют отдельного плана.</p><h2>С чего начать GitOps без лишней боли</h2><p>Не надо сразу переводить на GitOps весь кластер и каждую сервисную мелочь. Нормальный старт — один сервис, одно непроизводственное окружение и очень понятный путь изменений.</p><ol><li>Выберите один сервис или namespace и храните его манифесты, Helm values или Kustomize-конфигурацию в Git.</li><li>Подключите Argo CD или Flux CD и сначала добейтесь прозрачного diff и понятного sync-статуса, а не полной магии.</li><li>Зафиксируйте правило: изменения в production идут только через pull request, без ручных правок через kubectl.</li><li>Отдельно опишите rollback для миграций, данных и stateful-изменений: Git-rollback сам по себе не откатывает всё подряд.</li></ol><p>Когда команда привыкнет к этой дисциплине на одном сервисе, можно переносить на GitOps другие окружения и приложения. Самый плохой сценарий — внедрять красивый термин, не меняя review-процесс, ownership и работу с конфигурацией.</p><h2>Выводы</h2><p>GitOps — это не магическая кнопка и не синоним CI/CD. Это способ сделать деплой и конфигурацию прозрачнее: изменения проходят через Git, состояние среды сравнивается с репозиторием, а drift, откаты и расследования становятся понятнее. Особенно хорошо это работает там, где Kubernetes уже есть, а цена ручных действий в production быстро растёт.</p><p>Если вам ещё рано, сначала доберите базу: <a href="https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih">Git и GitHub</a>, <a href="https://tproger.ru/articles/chto-takoe-docker-prostymi-slovami--kontejnery--obrazy-i-docker-c">Docker</a>, <a href="https://tproger.ru/articles/chto-takoe-ci-cd--nepreryvnaya-integraciya-i-dostavka">CI/CD</a>, <a href="https://tproger.ru/articles/chto-takoe-kubernetes--orkestraciya-kontejnerov-prostymi-slovami">Kubernetes</a> и <a href="https://tproger.ru/articles/chto-takoe-helm-i-helm-charts--paketnyj-menedzher-dlya-kubernetes-p">Helm</a>. Если база уже есть и релизы всё ещё упираются в ручной доступ к кластеру, GitOps — логичный следующий шаг. А дальше уже можно разбираться с <a href="https://tproger.ru/articles/razbiraem-argocd--avtomatizirovannyj-deploj-v-kubernetes">Argo CD</a> и более сложными сценариями.</p><p>Для практики лучше держать рядом и официальные материалы: <a href="https://opengitops.dev/">OpenGitOps</a>, <a href="https://argo-cd.readthedocs.io/en/latest/">Argo CD</a> и <a href="https://fluxcd.io/">Flux CD</a>. Они помогут не перепутать общий принцип с конкретной реализацией.</p>]]></content:encoded>
    </item>
    <item>
      <title>Переосмысление пулл-реквестов: почему code review должен учить, а не только ловить баги</title>
      <link>https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--</link>
      <comments>https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--</guid>
      <description><![CDATA[<p>Как стековые PR, приоритет файлов в диффе и единая страница ревью сокращают comprehension debt. Перевод статьи создателя Lubeno о будущем code review.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--">Переосмысление пулл-реквестов: почему code review должен учить, а не только ловить баги</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Организация разработки]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 12:28:46 GMT</pubDate>
      <content:encoded><![CDATA[<p>Это перевод с адаптацией <a href="https://lubeno.dev/blog/reinventing-the-pull-request">статьи</a> Bernard Kolobara, автора платформы <a href="https://lubeno.dev">Lubeno</a>.</p><p>Пулл-реквесты задумывались как инструмент для совместной работы над кодом. На практике они превратились в бюрократическую процедуру: гигантские диффы, комментарии в разных вкладках, коллапсированные «outdated»-ветки обсуждений. Bernard Kolobara считает, что проблема не в самой идее code review, а в инструментах — и предлагает конкретные решения.</p><ul><li>Comprehension debt (долг понимания) — главная проблема, которую должен решать code review, а не только ловля багов</li><li>Стековые пулл-реквесты: разбиение изменений на мелкие самодостаточные коммиты, которые ревьюятся независимо</li><li>Приоритет файлов: тесты и зависимости показываются первыми в диффе через .gitattributes</li><li>Всё на одной странице: код и обсуждение вместе, без вкладок</li><li>ИИ не убил code review — он обнажил хрупкость инструментов, которые не справляются с растущим объёмом кода</li></ul><h2>Comprehension debt: долг понимания кода</h2><p>Addy Osmani <a href="https://addyosmani.com/blog/comprehension-debt/">описал</a> comprehension debt как разрыв между объёмом кода в проекте и тем, сколько из этого кода команда реально понимает. Чем больше разрыв — тем медленнее работа. Проектировать систему, которую полностью понимаешь, проще, чем ту, которую «примерно знаешь». С появлением ИИ-агентов в рабочих процессах этот разрыв значительно вырос.</p><p>Paul Graham в эссе <a href="https://paulgraham.com/greatwork.html">о великой работе</a> пишет, что лучшие идеи приходят вне клавиатуры — на прогулке, в душе, перед сном. Но для этого «фонового процессинга» нужно, чтобы контекст проекта уже был в голове. Сначала нужна осознанная работа с кодом.</p><p>Code review — идеальный момент для сокращения этого разрыва. Каждый ревью — возможность узнать, как кодовая база развивается, каковы её границы и ограничения. Не обязательно проверять каждую строку дифа — достаточно понять ключевые части, чтобы обновить ментальную модель. Ловля багов — лишь <a href="https://www.davidpoll.com/2026/02/code-review-is-not-about-catching-bugs">одна часть</a> ценности ревью.</p><h2>Как сократить разрыв: конкретные решения</h2><h3>Стековые пулл-реквесты</h3><p>Разбить большой PR на маленькие — самый эффективный способ помочь ревьюеру. В теории для этого подходят коммиты: каждый — самодостаточная единица, <a href="https://youtu.be/GOrKfCs-mr0?si=SWndwJF0IWOF-SG7&amp;t=102">рассказывающая историю</a>. На практике это не работает из-за Git.</p><p>Git заточен под append-only workflow. Вернуться в старый коммит и отредактировать его — мучительно. Даже если вы аккуратно структурировали историю, рано или поздно появляется серия коммитов «fix», «actual fix», «ok now really fix». Когда смотришь на отдельный коммит, не видишь полной картины — правки могут быть размазаны по нескольким коммитам дальше по истории.</p><p>Bernard и его коллега Luísa решают эту проблему с помощью <a href="https://docs.jj-vcs.dev/latest/">Jujutsu</a> — VCS, которая позволяет прыгнуть в любой коммит и отредактировать его на месте, а затем автоматически пропагирует изменения через всю историю. Это позволяет «вылепить» идеальную историю коммитов.</p><p>В Lubeno стековые PR детектятся автоматически. Каждый PR показывается как дифф относительно родительского PR — ревью и одобрение идут независимо. Автор не ждёт, пока предыдущий PR смёржат, и может продолжать работу.</p><h3>Приоритет файлов в диффе</h3><p>При ревью автор первым делом смотрит тесты: были ли изменены существующие, тестируют ли новые что-то полезное. Затем — зависимости: добавляется ли новая и зачем. Но все платформы для code review показывают файлы в алфавитном порядке — важные изменения легко пропустить в большом диффе.</p><p>Lubeno использует кастомный атрибут priority в .gitattributes (это не стандартный атрибут Git, а расширение Lubeno):</p><p>Файлы с высоким приоритетом показываются первыми на странице PR. Простое решение, но оно гарантирует, что самые важные изменения вы увидите сразу.</p><h3>Всё на одной странице</h3><p>Почти все платформы для code review разносят комментарии, коммиты и код по разным вкладкам. Автор признаётся: «Я нажимал на вкладку Commits только по ошибке — ни разу намеренно». Обсуждение тесно связано с кодом, но чтобы следить за ним, приходится постоянно скроллить наверх, переключать вкладки и искать нужный фрагмент.</p><p>В Lubeno нет вкладок на странице PR. Код и обсуждение живут в одном месте.</p><h2>Эволюция кода в рамках PR</h2><p>PR — не статичная сущность. Это место для обсуждения и итераций. Знакомая ситуация: вы оставили комментарий, вернулись — и обнаружили несколько новых коммитов, а все ваши комментарии свёрнуты как «outdated». Непонятно, учтены ли ваши замечания, что изменилось с момента вашего последнего просмотра.</p><p>Lubeno отслеживает комментарии к коду и наложение interdiff (разницу между версиями файла в рамках PR): если код был изменён более поздним коммитом (или force push), разница видна прямо в контексте комментария. Не нужно переключаться между вкладками, чтобы понять, что произошло.</p><h2>Будущее пулл-реквестов</h2><p>Некоторые <a href="https://boristane.com/blog/the-software-development-lifecycle-is-dead/">называют</a> PR «реликтом прошлого» и призывают от них отказаться. Автор не согласен: процесс ревью кода сегодня ценнее, чем когда-либо. ИИ не убил code review — он обнажил хрупкость инструментов. Больше строк кода просто сделали их непригодными.</p><p>Code review находится в идеальной точке жизненного цикла: после всей творческой работы и прямо перед продакшном. Это последний шанс разобраться, что именно поедет к пользователям. Если вы хотите создавать продукт, который радует пользователей, вам нужно понимать, что происходит в коде.</p><h2>Выводы</h2><p>Статья Bernard Kolobara — не абстрактные размышления, а описание конкретных решений, реализованных в <a href="https://lubeno.dev">Lubeno</a>. Даже если вы не планируете переходить с GitHub — идеи стековых PR, приоритета файлов и unified-страницы ревью стоит примерить к своему workflow.</p><p>Ключевой тезис: code review — не бюрократия, а инструмент обучения. Каждый ревью должен делать команду чуть умнее, а не просто ставить галочку.</p>]]></content:encoded>
    </item>
    <item>
      <title>Что такое Git и GitHub: руководство для начинающих</title>
      <link>https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih</link>
      <comments>https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih</guid>
      <description><![CDATA[<p>Что такое Git и GitHub: как работает VCS, основные команды, сравнение с GitLab и пошаговая инструкция для новичков. Начните работать с Git прямо сейчас.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih">Что такое Git и GitHub: руководство для начинающих</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 29 Mar 2026 05:09:28 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы только начинаете путь в разработке, то наверняка уже слышали слова «Git» и «GitHub» — они звучат на каждом собеседовании, в каждом туториале и в каждом open-source проекте. Но что это такое на самом деле и зачем это нужно? В этой статье разберём всё с нуля: от первой команды в терминале до создания собственного репозитория на GitHub.</p><h2>Что такое Git</h2><p><b>Git</b> — это распределённая система контроля версий (Version Control System, VCS), которая отслеживает изменения в файлах и позволяет нескольким разработчикам работать над одним проектом одновременно. Git был создан Линусом Торвальдсом в 2005 году для разработки ядра Linux и сегодня является стандартом индустрии: по данным Stack Overflow Developer Survey, его используют около 93–95% профессиональных разработчиков. С помощью Git можно в любой момент вернуться к предыдущей версии кода, сравнить изменения и объединить работу нескольких людей с минимумом конфликтов — хотя конфликты при слиянии (merge conflicts) иногда возникают, Git помогает их разрешить.</p><p>- Git — бесплатная и открытая система контроля версий, созданная в 2005 году
- Используется в более чем 93% профессиональных проектов по всему миру
- GitHub — это облачный хостинг для Git-репозиториев, а не сам Git
- Три состояния файла в Git: рабочая директория, staging area, репозиторий
- Основные команды: git init, git add, git commit, git push, git pull
- GitLab и Bitbucket — альтернативы GitHub с похожим функционалом
- Первый коммит можно сделать за 5 минут после установки</p><h2>Зачем нужна система контроля версий</h2><p>Представьте: вы работаете над проектом и случайно удаляете важный файл или ломаете рабочий функционал. Без системы контроля версий восстановить данные практически невозможно. Именно для таких ситуаций и создавались VCS.</p><p>Вот основные задачи, которые решает Git:</p><ul><li>История изменений — вы видите, кто, когда и что изменил в коде</li><li>Откат к предыдущей версии — если новый код сломал проект, достаточно одной команды</li><li>Параллельная работа — несколько человек могут работать над разными частями проекта одновременно</li><li>Эксперименты без риска — создайте отдельную ветку, попробуйте идею, и если не понравится — просто удалите ветку</li><li>Резервное копирование — код хранится не только локально, но и в удалённом репозитории</li></ul><h2>Как работает Git</h2><p>Git управляет файлами через три уровня. Понимание этой модели — ключ к тому, чтобы не путаться в командах и не терять изменения.</p><h3>Рабочая директория (Working Directory)</h3><p>Это обычная папка на вашем компьютере с файлами проекта. Здесь вы пишете и редактируете код. Git следит за изменениями, но пока не сохраняет их в историю — файлы просто находятся в состоянии «изменён» или «не отслеживается».</p><h3>Staging Area (индекс)</h3><p>Промежуточная зона, куда вы добавляете файлы перед сохранением. Думайте о ней как о корзине для покупок: вы выбираете нужные товары (изменения) и кладёте их туда, прежде чем оформить заказ (сделать коммит). Команда git add перемещает файлы в staging area.</p><h3>Репозиторий и коммиты</h3><p>Когда вы выполняете команду git commit, Git делает снимок всех файлов из staging area и сохраняет его в историю репозитория. Каждый коммит — это точка в истории проекта с уникальным идентификатором (SHA-хешем), автором, датой и сообщением. В любой момент можно вернуться к любому коммиту.</p><blockquote>Ключевое отличие Git от большинства других VCS — распределённость. Каждый разработчик хранит полную копию репозитория со всей историей локально. Это означает, что можно работать офлайн и не зависеть от центрального сервера.</blockquote><h2>Основные команды Git</h2><p>Большинство повседневных задач решается с помощью 7–10 команд. Разберём их по порядку.</p><h3>git init — создать репозиторий</h3><p>Инициализирует новый Git-репозиторий в текущей папке. После выполнения команды появится скрытая папка .git, в которой Git хранит всю историю. Папку .git удалять нельзя — в ней хранится вся история проекта.</p><h3>git add и git status — добавить файлы в staging area</h3><p>Команда git status показывает текущее состояние репозитория — какие файлы изменены, какие добавлены в staging area. Команда git add добавляет файлы в staging area.</p><h3>git commit — сохранить изменения</h3><p>Создаёт коммит из файлов, добавленных в staging area. Сообщение коммита должно кратко описывать, что именно изменилось. Хороший формат: глагол в повелительном наклонении + что сделано.</p><h3>git push и git pull — синхронизация с удалённым репозиторием</h3><p>Команда git push отправляет локальные коммиты на удалённый сервер (например, GitHub). Команда git pull загружает изменения с сервера и объединяет их с локальной версией.</p><h3>git branch и git merge — ветки</h3><p>Ветки — одна из самых мощных функций Git. Ветка — это независимая линия разработки. Вы можете создать ветку для новой функциональности, работать в ней, не затрагивая основной код, а потом объединить (merge) с главной веткой.</p><h2>Что такое GitHub</h2><p><b>GitHub</b> — это облачная платформа для хостинга Git-репозиториев. Если Git — это инструмент на вашем компьютере, то GitHub — это место в интернете, где вы храните свой код и делитесь им с другими. Главная страница GitHub — github.com — основана в 2008 году и сегодня насчитывает более 100 миллионов разработчиков и свыше 420 миллионов репозиториев.</p><p>GitHub добавляет поверх Git множество удобных возможностей:</p><ul><li>Pull Request (PR) — предложение изменений с обсуждением кода перед слиянием</li><li>Issues — система задач и багов прямо внутри репозитория</li><li>Actions — автоматизация: тесты, деплой, сборка при каждом коммите</li><li>GitHub Pages — бесплатный хостинг статических сайтов прямо из репозитория</li><li>Discussions — форум для обсуждений внутри проекта</li><li>Code Review — удобный интерфейс для ревью кода с комментариями к строкам</li></ul><blockquote>Git — это технология, а GitHub — это сервис поверх этой технологии. Можно использовать Git без GitHub (например, хранить репозиторий на собственном сервере), но нельзя использовать GitHub без Git.</blockquote><h2>Git vs GitHub vs GitLab vs Bitbucket</h2><p>Разработчики часто путают эти понятия. Вот краткое сравнение четырёх основных инструментов экосистемы.</p><ul><li>Git — локальная система контроля версий, работает без интернета, устанавливается на компьютер</li><li>GitHub — крупнейший хостинг для Git-репозиториев, принадлежит Microsoft с 2018 года, идеален для open-source</li><li>GitLab — альтернатива GitHub с упором на DevOps, есть self-hosted версия, популярен в корпоративной среде</li><li>Bitbucket — продукт Atlassian (Jira, Confluence), хорошо интегрируется с их экосистемой, популярен в командах</li></ul><p>Для новичков рекомендуем начать с GitHub: он самый популярный, имеет лучшую документацию на русском языке и огромное сообщество. Бесплатный план включает неограниченное количество публичных и приватных репозиториев.</p><h2>Как начать работать с Git: пошаговая инструкция</h2><p>Следуйте этой инструкции, и через 10–15 минут у вас будет первый репозиторий на GitHub.</p><h3>Шаг 1. Установка Git</h3><ul><li>Windows: скачайте установщик с git-scm.com/download/win и запустите его</li><li>macOS: откройте терминал и выполните brew install git (или xcode-select --install)</li><li>Linux (Ubuntu/Debian): sudo apt install git</li></ul><h3>Шаг 2. Настройка имени и почты</h3><p>Git подписывает каждый коммит вашим именем и почтой. Настройте их один раз — они будут использоваться во всех проектах.</p><h3>Шаг 3. Создать аккаунт на GitHub</h3><p>Перейдите на github.com, нажмите «Sign up» и заполните форму регистрации. Выберите бесплатный тарифный план — для начинающих он полностью достаточен.</p><h3>Шаг 4. Создать первый репозиторий и сделать коммит</h3><h2>Выводы</h2><p>Git — это не просто инструмент для разработчиков, это основа профессиональной работы с кодом. Без него невозможно представить ни командную разработку, ни open-source проекты, ни современный DevOps. Хорошая новость: базовые команды можно освоить за один вечер, а дальше — практика и опыт.</p><p>Что делать дальше:</p><ol><li>Установите Git и создайте аккаунт на GitHub прямо сейчас</li><li>Сделайте первый репозиторий по инструкции из этой статьи</li><li>Попрактикуйтесь с ветками: создайте ветку, внесите изменения, слейте в main</li><li>Попробуйте сделать Pull Request в любой open-source проект — даже исправление опечатки в README считается</li><li>Изучите команды git stash, git cherry-pick и git bisect — они пригодятся на следующем уровне</li></ol><p>Знание Git сегодня — обязательное требование для любого разработчика. Если вы только начинаете — это один из первых инструментов, который нужно освоить. Если уже работаете — углубляйтесь в продвинутые возможности: rebase, stash, cherry-pick, подмодули. Подробнее о всех возможностях можно прочитать в <a href="https://git-scm.com/book/ru">официальной документации Git</a>.</p><p>Git лежит в основе всей современной DevOps-экосистемы. Следующий шаг — освоить <a href="https://tproger.ru/articles/chto-takoe-docker-prostymi-slovami--kontejnery--obrazy-i-docker-c">Docker</a> для контейнеризации приложений: именно связка Git + Docker образует фундамент любого CI/CD-пайплайна. А если хотите автоматизировать тестирование и доставку кода — читайте нашу статью о том, <a href="https://tproger.ru/articles/chto-takoe-ci-cd--nepreryvnaya-integraciya-i-dostavka">что такое CI/CD</a>.</p><p>Если хотите собрать из Git, Docker, CI/CD, Kubernetes и Helm единый маршрут, посмотрите <a href="https://tproger.ru/articles/roadmap-devops-inzhenera-v-2026-godu--chto-uchit-i-v-kakom-poryadke">план обучения DevOps-инженера</a>. Там видно, почему Git идёт первым и как из него вырастает вся следующая цепочка инструментов.</p>]]></content:encoded>
    </item>
    <item>
      <title>Заглянуть под капот ИИ-агентов: новый инструмент раскрывает «магию» Claude Code</title>
      <link>https://tproger.ru/news/zaglyanut-pod-kapot-ii-agentov--novyj-instrument-raskryvaet--mag</link>
      <comments>https://tproger.ru/news/zaglyanut-pod-kapot-ii-agentov--novyj-instrument-raskryvaet--mag?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Неопознанный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/zaglyanut-pod-kapot-ii-agentov--novyj-instrument-raskryvaet--mag</guid>
      <description><![CDATA[<p>Появился Coding Agent Explorer: инструмент раскрывает, как Claude Code читает файлы, вызывает инструменты и тратит токены при разработке</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/zaglyanut-pod-kapot-ii-agentov--novyj-instrument-raskryvaet--mag">Заглянуть под капот ИИ-агентов: новый инструмент раскрывает «магию» Claude Code</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Промпты]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 19 Feb 2026 11:05:51 GMT</pubDate>
      <content:encoded><![CDATA[<p>ИИ-агенты любят создавать ощущение магии. Например, вы даете задачу — «добавь авторизацию через JWT». Затем минуту смотрите на мигающий курсор, после чего внезапно появляются изменения в семи файлах, новые тесты и коммит. Что происходило все это время — остается за кадром.</p><p>Шведский разработчик Торе Нестениус решил <a href="https://nestenius.se/ai/introducing-the-coding-agent-explorer-net/">сорвать</a> занавес. Он <a href="https://github.com/tndata/CodingAgentExplorer" rel="nofollow">выпустил</a> Coding Agent Explorer — открытый прокси-сервер, который в реальном времени показывает все общение между агентом и API Anthropic.</p><p>Сейчас поддерживается только Claude Code, но уже в таком виде инструмент дает неожиданно глубокое понимание того, как работает агентная разработка.</p><h2>Что именно он показывает</h2><p>Explorer перехватывает HTTP-запросы и визуализирует:</p><ul><li>системные промпты (часто намного длиннее, чем кажется);</li><li>последовательность вызовов инструментов (Read, Grep, Write, Bash);</li><li>шаги «размышления» агента;</li><li>распределение задач между моделями (например, Haiku для рутинных операций и Sonnet/Opus для сложной логики);</li><li>статистику токенов, включая кэш (cache_creation_tokens и cache_read_tokens).</li></ul><p>По сути, инструмент можно воспринимать как «рентген для агентной разработки». Видно, какие файлы агент читает, как ищет паттерны в коде, почему он внезапно запускает тесты и сколько это стоит в токенах.</p><p>В интерфейсе два режима. HTTP Inspector — сухая таблица со всеми JSON-телами, временем ответа и расходом токенов. Conversation View — более «человеческий» режим, где процесс выглядит как диалог: шаги планирования, проверки гипотез, исправления ошибок.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2026-02-19/a137b978-5b64-416e-a3a5-d4302b1937b7.webp" alt="" /></figure><h2>Зачем это нужно</h2><p>Изначально инструмент задумывался как учебный — автор использует его на воркшопах по агентной разработке. Но практическая ценность оказалась шире.</p><p>Когда агент «зависает», теперь можно увидеть, что он на самом деле делает: перебирает файлы, пересобирает контекст или тратит половину лимита токенов на анализ README.</p><p>А уже это помогает оптимизировать промпты и понимать реальную стоимость задач. В итоге ИИ перестает быть черным ящиком.</p><h2>Безопасность и ограничения</h2><p>Explorer работает только локально (localhost). API-ключи автоматически маскируются в интерфейсе.</p><p>Данные не сохраняются — все хранится в памяти и ограничено примерно тысячей запросов. Никаких внешних сервисов и баз данных.</p>]]></content:encoded>
    </item>
    <item>
      <title>Маск: «ИИ будет создавать бинарники напрямую» — программирование якобы уйдет в прошлое</title>
      <link>https://tproger.ru/news/mask---ii-budet-sozdavat-binarniki-napryamuyu----programmirovanie</link>
      <comments>https://tproger.ru/news/mask---ii-budet-sozdavat-binarniki-napryamuyu----programmirovanie?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/mask---ii-budet-sozdavat-binarniki-napryamuyu----programmirovanie</guid>
      <description><![CDATA[<p>Маск заявил, что ИИ скоро будет создавать бинарники напрямую, но эксперты сомневаются в отказе от исходного кода и компиляторов</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/mask---ii-budet-sozdavat-binarniki-napryamuyu----programmirovanie">Маск: «ИИ будет создавать бинарники напрямую» — программирование якобы уйдет в прошлое</a>»</p>]]></description>
      <category><![CDATA[Компиляторы]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Илон Маск]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 17 Feb 2026 02:17:09 GMT</pubDate>
      <content:encoded><![CDATA[<p>Илон Маск <a href="https://timesofindia.indiatimes.com/technology/tech-news/elon-musk-gives-less-than-a-year-to-coding-as-a-profession-says-there-is-no/articleshow/128244238.cms" rel="nofollow">заявил</a> на встрече с сотрудниками xAI, что уже к концу 2026 года «никто не будет писать код». Якобы ИИ сможет создавать бинарные файлы напрямую.</p><p>По его словам, нейросеть сможет делать это даже эффективнее традиционных компиляторов.</p><p>Звучит громко. Но если разобрать тезис технически, все не так однозначно.</p><h2>Что именно предлагает Маск</h2><p>По словам миллиардера, вместо привычной цепочки «исходный код → компилятор → бинарник», ИИ будет получать задачу и сразу выдавать исполняемый файл. Без промежуточного слоя в виде читаемого кода.</p><p>Фактически это означает отказ от исходников как основного артефакта разработки. Промпт на входе, а .exe или ELF на выходе.</p><h2>Почему это спорно с технической точки зрения</h2><p>Компиляторы — это детерминированные системы. Они проверяют синтаксис и типы, строят промежуточное представление программы, применяют оптимизации и гарантируют воспроизводимый результат.</p><p>Один и тот же код при одинаковых условиях дает один и тот же бинарник.</p><p>LLM работают иначе: они генерируют вероятностный результат. Малейшая ошибка в бинарнике приведет к падению программы или трудноуловимому багу.</p><p>В отличие от исходного кода, бинарный файл невозможно нормально ревьюить, сравнивать в Git или проверять на уровне логики.</p><p>Кроме того, компиляция стоит дешево — это миллисекунды CPU. Генерация крупных бинарников через LLM потребовала бы миллионов токенов и значительно больших вычислительных затрат.</p><h2>Где ИИ действительно меняет разработку</h2><p>На фоне громких заявлений Маска, многие как будто забыли, что ИИ уже активно используется в программировании. Но в другом формате. Технология помогает писать исходный код, объяснять сложные участки, генерировать тесты, предлагать рефакторинг.</p><p>А дальше в дело все равно вступает компилятор — как проверяемый и предсказуемый этап.</p><p>Более реалистичный сценарий — улучшение компиляторов с помощью ИИ, а не их замена. Например, автоматический подбор оптимизаций или более агрессивная векторизация.</p>]]></content:encoded>
    </item>
    <item>
      <title>В VS Code нашли дыру, дающую бесплатный доступ к платным ИИ-агентам</title>
      <link>https://tproger.ru/news/v-vs-code-nawli-dyru--dayushhuyu-besplatnyj-dostup-k-platnym-ii-agen</link>
      <comments>https://tproger.ru/news/v-vs-code-nawli-dyru--dayushhuyu-besplatnyj-dostup-k-platnym-ii-agen?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/v-vs-code-nawli-dyru--dayushhuyu-besplatnyj-dostup-k-platnym-ii-agen</guid>
      <description><![CDATA[<p>В VS Code нашли дыру в Copilot: обход биллинга дает бесплатный доступ к платным ИИ-агентам через subagent-режим</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/v-vs-code-nawli-dyru--dayushhuyu-besplatnyj-dostup-k-platnym-ii-agen">В VS Code нашли дыру, дающую бесплатный доступ к платным ИИ-агентам</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 04 Feb 2026 11:30:16 GMT</pubDate>
      <content:encoded><![CDATA[<p>В VS Code обнаружили уязвимость, которая позволяет получать практически неограниченный доступ к платным ИИ-моделям. При этом «премиум-запросы» не списываются.</p><p>Об этом <a href="https://github.com/microsoft/vscode/issues/292452">сообщил</a> пользователь GitHub под ником Angry-Orangutan, опубликовав подробный баг-репорт в публичном репозитории Microsoft.</p><p>Проблема затрагивает новый режим agent / subagent в Copilot и связана не с безопасностью в классическом смысле, а с биллингом. Тем не менее, эффект от нее вполне материальный: дорогие модели вроде Claude Opus можно использовать бесплатно и сколько угодно долго.</p><h2>Как работает обход биллинга</h2><p>Механизм уязвимости строится на нескольких допущениях в архитектуре Copilot.</p><p>Во-первых, стоимость запроса рассчитывается только по первой модели, которая принимает сообщение. Во-вторых, запуск подагентов (subagents) и вызовы инструментов не учитываются как отдельные платные операции.</p><p>В результате пользователь может начать чат с «бесплатной» моделью, например GPT-5 Mini, а затем внутри нее создать подагента, явно указав для него уже премиум-модель.</p><p>Дальше все просто: бесплатная модель делегирует работу подагенту, а тот выполняет задачи с помощью Opus или другого дорогого ИИ — без списания лимитов. По словам автора отчета, таким способом он запускал сотни подагентов и часами обрабатывал файлы, потратив всего несколько платных кредитов.</p><h2>Реакция Microsoft</h2><p>Интересно, что изначально исследователь пытался передать проблему через MSRC — стандартный канал ответственного раскрытия уязвимостей. Однако там ответили, что «обход биллинга не относится к сфере безопасности» и предложили оформить баг публично.</p><p>В итоге issue действительно появилась в открытом репозитории VS Code, но довольно быстро была закрыта со статусом «not planned». Это означает, что компания не обещает что-либо исправить и уж тем более не комментирует сроки.</p><p>Это решение вызвало волну иронии в обсуждении: пользователи отметили, что Microsoft фактически оставила инструкцию по бесплатному использованию платных моделей в открытом доступе.</p><h2>Почему это важно</h2><p>Формально речь идет не о взломе, а о логической ошибке в расчете стоимости запросов. Но на практике уязвимость подрывает саму модель монетизации Copilot и агентных функций VS Code.</p>]]></content:encoded>
    </item>
    <item>
      <title>Линус Торвальдс впервые описал, что будет с Linux без него</title>
      <link>https://tproger.ru/news/linus-torvalds-vpervye-opisal--chto-budet-s-linux-bez-nego</link>
      <comments>https://tproger.ru/news/linus-torvalds-vpervye-opisal--chto-budet-s-linux-bez-nego?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/linus-torvalds-vpervye-opisal--chto-budet-s-linux-bez-nego</guid>
      <description><![CDATA[<p>Линус Торвальдс впервые описал план преемственности Linux на случай своего ухода и коллективное управление ядром проекта</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/linus-torvalds-vpervye-opisal--chto-budet-s-linux-bez-nego">Линус Торвальдс впервые описал, что будет с Linux без него</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 28 Jan 2026 09:42:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>В репозитории ядра Linux появился <a href="https://github.com/torvalds/linux/commit/102606402f4f5943266160e263c450fdfe4dd981#diff-6c81210e8795b03502471e1435cac0763110f72b823038bd0033eb617c15ab8d" rel="nofollow">документ</a>, которого раньше не существовало.</p><p>Линус Торвальдс закоммитил файл Project continuity — формальный план действий на случай, если он больше не сможет выполнять роль главного мейнтейнера проекта.</p><p>Переживать не стоит — пока что речи о скором уходе или передаче власти «наследнику» не идет. Документ скорее фиксирует то, как сообщество должно действовать в кризисной ситуации — внезапной и без предварительной подготовки.</p><p>Ранее подобные вопросы в Linux решались негласно и на уровне доверия, но теперь процесс впервые описан письменно.</p><h2>Почему это вообще понадобилось</h2><p>Linux — распределенный проект с сотнями мейнтейнеров, но финальная точка принятия решений по-прежнему сходится в одном месте: в основном репозитории ядра.</p><p>Исторически эту роль выполняет сам Торвальдс. Именно он принимает изменения в mainline и определяет, что считается «официальным» Linux.</p><p>В коммите напрямую упоминается релиз 4.19 в 2018 году — момент, когда Торвальдс временно отошел от проекта.</p><p>Тогда стало очевидно, что даже при развитой системе мейнтейнеров отсутствие одного человека создает управленческую неопределенность. Новый документ — попытка эту неопределенность устранить.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2026-01-28/02bf2609-9870-459d-87b3-614f41f79c2c.webp" alt="" /></figure><h2>Как выглядит план преемственности</h2><p>Если кратко, Linux не переходит под контроль одного нового лидера автоматически. Вместо этого запускается процесс коллективного управления.</p><p>Организатор последнего Linux Maintainers Summit обязан в течение 72 часов собрать обсуждение с участниками саммита и Technical Advisory Board (TAB) Linux Foundation.</p><p>Эта группа рассматривает варианты дальнейшего управления репозиторием: временные или постоянные, индивидуальные или коллегиальные.</p><p>Ключевая цель формулируется прямо в тексте — сохранить долгосрочное здоровье проекта и сообщества, а не просто «назначить замену».</p><p>Если саммит давно не проводился, состав участников определяет TAB. Через две недели после встречи, сообщество получает публичное разъяснение дальнейших шагов через официальную рассылку kernel.org.</p>]]></content:encoded>
    </item>
    <item>
      <title>В Кремниевой долине сотрудников начали заменять на Mac mini с установленным ИИ-ботом</title>
      <link>https://tproger.ru/news/v-kremnievoj-doline-sotrudnikov-nachali-zamenyat-na-mac-mini-s-us</link>
      <comments>https://tproger.ru/news/v-kremnievoj-doline-sotrudnikov-nachali-zamenyat-na-mac-mini-s-us?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/v-kremnievoj-doline-sotrudnikov-nachali-zamenyat-na-mac-mini-s-us</guid>
      <description><![CDATA[<p>В Кремниевой долине стартапы заменяют сотрудников на Mac mini с ИИ-ботом Clawdbot, который работает 24/7 и берет на себя рутину</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/v-kremnievoj-doline-sotrudnikov-nachali-zamenyat-na-mac-mini-s-us">В Кремниевой долине сотрудников начали заменять на Mac mini с установленным ИИ-ботом</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Стартапы]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Notion]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 26 Jan 2026 06:50:10 GMT</pubDate>
      <content:encoded><![CDATA[<p>В Кремниевой долине появился новый мем, который стремительно перестает быть шуткой.</p><p>Стартапы начали скупать Mac mini и использовать их не как персональные компьютеры, а как круглосуточных цифровых сотрудников. На этих машинах крутится <a href="https://github.com/clawdbot/clawdbot" rel="nofollow">Clawdbot</a> — ИИ-ассистент, который берет на себя рутину и работает без выходных.</p><h2>Mac mini как «железный сотрудник»</h2><p>Компактный компьютер от Apple неожиданно оказался идеальным форматом для ИИ-работника.</p><p>Он тихий, энергоэффективный и может быть включен 24/7. В результате Mac mini стали использовать как отдельные рабочие узлы: один — для коммуникаций, другой — для автоматизации задач, третий — для интеграций с сервисами.</p><p>В некоторых офисах уже собирают целые стойки из Mac mini. Каждый такой «миник» выполняет строго определенную функцию, а в сумме они заменяют несколько операционных ролей внутри команды.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2026-01-26/c44147c4-409d-4d1c-abe1-4c97a19ec164.webp" alt="" /></figure><h2>Во главе угла — Clawdbot</h2><p>В сети Clawdbot частенько сравнивают с ассистентом Тони Старка — Джарвисом. Причин тому несколько. Так, это не просто чат с нейросетью, а полноценный помощник, который умеет работать с приложениями, файлами и сервисами так, как это делал бы человек.</p><p>Он пишет и отвечает на сообщения в мессенджерах, управляет файлами на компьютере, автоматизирует повторяющиеся действия и взаимодействует с популярными сервисами вроде Gmail, Notion или GitHub.</p><p>При этом бот запоминает контекст, учитывает предыдущие действия и постепенно подстраивается под стиль работы конкретной команды.</p><p>Ключевой момент — Clawdbot живет локально, на отдельной машине. Да, это не облачный ассистент, принадлежащий какой-то крупной компании.</p><h2>Почему стартапы выбирают именно такой формат</h2><p>Использование Mac mini вместо облачных серверов или виртуальных рабочих столов оказалось неожиданно практичным. Машины легко масштабировать, они не требуют сложной инфраструктуры и обходятся дешевле в долгосрочной перспективе. Один раз купил, настроил и получил «сотрудника», который всегда на месте.</p>]]></content:encoded>
    </item>
    <item>
      <title>Docs-as-Code на практике: автоматизация сборки документации в ODS проекте</title>
      <link>https://tproger.ru/articles/docs-as-code-na-praktike--avtomatizaciya-sborki-dokumentacii-v-ods-proekte</link>
      <comments>https://tproger.ru/articles/docs-as-code-na-praktike--avtomatizaciya-sborki-dokumentacii-v-ods-proekte?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Владимир]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/docs-as-code-na-praktike--avtomatizaciya-sborki-dokumentacii-v-ods-proekte</guid>
      <description><![CDATA[<p>В статье рассказывается о переходе к подходу "Docs‑as‑Code" на примере проекта ODS (Open Documentation Standard). Приводится краткое описание функциональных возможностей проекта ODS.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/docs-as-code-na-praktike--avtomatizaciya-sborki-dokumentacii-v-ods-proekte">Docs-as-Code на практике: автоматизация сборки документации в ODS проекте</a>»</p>]]></description>
      <category><![CDATA[Автоматизирование]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 03 Jan 2026 10:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>В статье рассказывается о переходе к подходу "Docs‑as‑Code" на примере проекта <a href="https://gitlab.com/vvvnik/ods-project">ODS</a> (Open Documentation Standard).</p><p>Рассматриваются причины отказа от "Word" подобных инструментов и выбор языка разметки текста <a href="https://docs.asciidoctor.org/asciidoc/latest/">AsciiDoc</a>.</p><p>Приводится краткое описание функциональных возможностей проекта ODS, версионирование документации в Git, парсинг данных из внешних источников, преобразование и перевод атрибутов БД с помощью LLM-моделей, автоматизация сборки комплектов документов, формирование PDF и публикация документации на сайте используя генератор статических сайтов – <a href="https://docs.antora.org/antora/latest/">Antora</a>.</p><p>Проект ODS (Open Documentation Standard) – открытый стандарт и инструментарий для автоматизации процессов создания и поддержки технической документации в ИТ и других проектах. Проект не связан с форматом OpenDocument Spreadsheet (.ods) или проектами Open Data.</p><p>В открытом доступе находятся <a href="https://gitlab.com/vvvnik/ods-project">репозиторий</a> и <a href="https://vvvnik.gitlab.io/ods-project/project-guide/1/index.html">сайт</a> проекта.</p><h2>Проблемы технической документации</h2><p>Документация живёт в отдельных файлах, «шаблоны ГОСТ» лежат где‑то в сетевой папке, согласования идут в чате или почте, а изменения в файлах превращаются в бесконечные:</p><p>финал_финал_2_исправлено_после_замечаний.docx</p><p>С подобными "Word" инструментами всё хорошо, пока документация не развивается и не требует постоянной актуализации. Но когда проекты растут и появляются новые версии, возникают типичные проблемы:</p><ul><li>Проверка и комментарии – сравнение документов плохо похоже на ревью кода, комментарии живут отдельно от истории изменений.</li><li>Повторное использование – «вставить в 17 документов один и тот же фрагмент» почти всегда приводит к поломке стилей и форматированию.</li><li>Стандартизация – трудно гарантировать, что все документы собраны одинаково и в соответствии с шаблонами</li><li>Сборка комплектов – ГОСТ‑комплекты, ведомости и спецификации обычно собираются вручную.</li></ul><h2>Требования к документированию</h2><p>Для решения подобных проблем необходимо чтобы документация разрабатывалась как код:</p><ul><li>хранилась в одном месте и версионировалась;</li><li>прозрачно проходила ревью;</li><li>имела единую структуру и возможность повторного использования текста;</li><li>могла синхронизироваться с разработкой – например, отражать актуальное состояние БД и API;</li><li>автоматически собиралась в комплект с едиными стандартами оформления.</li></ul><p>Рассматривалось несколько вариантов решения. Поскольку подобных статей достаточно много, перейдем к следующему разделу.</p><h2>Выбор пал на AsciiDoc и его инфраструктуру</h2><p>Для большого массива технической документации необходимо иметь следующий функционал:</p><ul><li>include – сборка документа из блоков;</li><li>атрибуты – объявление переменных и констант с повторным использованием;</li><li>сложные таблицы – заголовки, объединение и выравнивание ячеек;</li><li>ссылки между разделами и файлами с контролируемыми наименованиями;</li><li>диаграммы – возможность встраивать UML и BPMN без скриншотов;</li><li>кастомизация стилей оформления;</li><li>кросс‑компиляция в HTML и PDF.</li></ul><p>Открытая экосистема Asciidoctor позволяет максимально реализовать эти требования. Язык разметки AsciiDoc предоставляет мощные средства форматирования контента, а инструменты с открытым исходным кодом дают возможность гибко кастомизировать сборку документации под разные требования.</p><h2>Проект ODS (Open Documentation Standard)</h2><p>ODS – это не «ещё один стандарт документации». Это попытка собрать воедино подход "Docs‑as‑Code" для документирования проектов.</p><p>Проект должен был соответствовать следующим требованиям:</p><ul><li>единый формат исходного кода документации;</li><li>автоматизация сборки документов и комплектов;</li><li>генерация частей документации из БД и OpenAPI;</li><li>использование LLM‑моделей для рутинных задач;</li><li>публикация документации на сайте с печатными формами.</li></ul><p>Структура репозитория построена на основе проекта Antora, которая позволяет собирать компоненты сайта из разных репозиториев, веток и тегов, не переключаясь между ними. Остальные инструменты адаптируются под такую структуру.</p><h3>Как устроен репозиторий</h3><p>Репозиторий содержит следующие основные папки проекта:</p><ul><li>components/ – компоненты документации (по смыслу: сервисы, системы, гайды);</li><li>components/&lt;name&gt;/modules/&lt;module&gt;/pages – страницы (Antora формирует HTML из pages);</li><li>components/&lt;name&gt;/modules/&lt;module&gt;/partials – переиспользуемые фрагменты текста, подключаемые через include:: (из partials HTML не формируется);</li><li>docker/ – скрипты для локальной сборки и запуска Docker-образов необходимых для сборки проекта;</li><li>tools/ – Ruby‑инструменты автоматизации и конфигурации;</li><li>templates/ – шаблоны документации;</li><li>antora-playbook.yml – файл конфигурации Antora.</li></ul><p>Такая структура позволяет реализовать модульность документации и параллельно вести несколько проектов или систем в одном репозитории.</p><p>Система контроля версий (Git) позволяет поддерживать версии комплектов документации используя теги и ветки.</p><h3>Автоматизация в ODS</h3><p>Теперь про то, что обычно «ломает» мечту о "Docs‑as‑Code":</p><ul><li>печать по ГОСТ;</li><li>автоматическая генерация контента из БД и API;</li><li>сборка всего комплекта документов.</li></ul><p>Главный оркестратор – скрипт tools/start.rb проходит по компонентам из файла конфигурации и, в зависимости от флагов, выполняет:</p><ul><li>Конвертацию BPMN (Node + Puppeteer);</li><li>Конвертацию Draw.io (Node);</li><li>Генерацию AsciiDoc из OpenAPI / Swagger (Ruby);</li><li>Генерацию AsciiDoc и диаграмм из PostgreSQL, преобразование и перевод атрибутов (Ruby, Ollama);</li><li>Генерацию служебных списков, ссылок и таблиц о составе документации, имен файлов и названий документов, количестве листов в документах и т.п. (Ruby);</li><li>Генерацию листов утверждения, спецификаций и ведомостей (Ruby, Asciidoctor PDF);</li><li>Генерацию PDF (Asciidoctor PDF + кастомные конвертеры).</li></ul><p>Запуск командой:</p><p>ruby tools/start.rb</p><p>Запускается скрипт start.rb и выполняется сборка проекта согласно сценарию, заданному в файле config.yml. В результате сборки проекта появляются готовые к печати и/или публикации на сайте PDF документы.</p><h3>Формирование PDF документов</h3><p>Инструменты <a href="https://docs.asciidoctor.org/pdf-converter/latest/">Asciidoctor PDF</a> предоставляют широкие возможности настройки тем оформления документов, но оформление в соответствии с ГОСТ или шаблонами часто упирается в проблемы:</p><ul><li>рамки и штампы;</li><li>нестандартные титульные страницы;</li><li>особые правила нумерации списков и колонтитулов.</li></ul><p>Поэтому в ODS генерация PDF построена так:</p><ol><li>Asciidoctor PDF делает базовую вёрстку контента;</li><li>Кастомные Ruby‑конвертеры оформляют рамки, титульные страницы, листы утверждения и стилизуют списки.<br /></li></ol><p>На выходе получается документация оформленная в соответствии с заложенными к ее оформлению требованиями.</p><h3>Документация из внешних источников</h3><p>В настоящее время ODS поддерживает генерацию документации из следующих источников:</p><ol><li>PostgreSQL – таблицы, поля, комментарии, ERD‑диаграммы;</li><li>OpenAPI / Swagger – структура API, методы, параметры и ответы (могут использоваться как ссылки на swagger, так и файлы в в репозитория json/yml).</li></ol><p>В результате парсинга БД и API формируются отдельные asciidoc документы для подключения к основным файлам документации.</p><h3>Модели ИИ и Ollama</h3><p>Для преобразования и перевода названий таблиц и атрибутов в полученной документации, при незаполненных в БД полях <i>comment</i>, используется словарь переводов и сервер <a href="https://ollama.com/">Ollama</a> предоставляющий CLI и HTTP API с различными языковыми моделями (LLM).</p><p>Для задач преобразования и перевода используется промт-файл <i>database_translations.prompt</i>, который отправляется в модель вместе с данными.</p><p>Словарь это yml-файл генерируемый скриптом который в свою очередь использует сервис Ollama. При последующих переводах словарь имеет приоритет, а LLM используется пакетно, что позволяет сохранить точность и обеспечить приемлемую скорость при повторных переводах.</p><p>Словарь можно править вручную. При появлении новых данных в БД, они транслируются в лог-файл tools/log/database_translations_log.txt.</p><p>Логирование удобно для контроля перевода, а при необходимости и ручной правки последних изменений в словаре. Язык перевода может быть задан в файле config.yml в зависимости от используемого в БД.</p><h3>Сайт документации и Antora</h3><p>Для публикации документации используется генератор статических сайтов Antora. Он обеспечивает:</p><ul><li>компонентную модель документации;</li><li>встроенное версионирование;</li><li>сборку сайта из разных репозиториев, веток и тегов;</li><li>поддержку диаграмм через сервер Kroki.</li></ul><p>Автоматически сформированные на предыдущем этапе списки используются Antora для формирования ссылок в навигации и к сформированным PDF‑документам.</p><p>Запуск командой:</p><p>antora antora-playbook.yml</p><p>Antora в ODS отвечает только за сборку сайта. Файл конфигурации antora-playbook.yml используется для самой Antora и установки атрибутов-ключей для условных операторов в Asciidoc и Ruby, которые разделяют сборку PDF и сайта.</p><h2>Итог</h2><p>ODS – это попытка сделать техническую документацию:</p><ol><li>воспроизводимой;</li><li>версионируемой;</li><li>связанной с реальными источниками данных;</li><li>удобной для проверки;</li><li>автоматически собираемой в готовый комплект.</li></ol><p>На практике это помогает поддерживать документацию в актуальном состоянии, ускоряет погружение в проект новых сотрудников, а масштабирование проекта не превращает его документацию в “кладбище файлов”.</p><p>Если вы хотите повторить этот подход у себя, практический совет прост: начните с AsciiDoc, подключите Git, научитесь собирать PDF. Всё остальное можно подключать постепенно, когда появится стабильная и понятная структура документации.</p><p>Реализацию проекта ODS и публикуемую с его помощью документацию можно посмотреть в открытом <a href="https://gitlab.com/vvvnik/ods-project">репозитории</a> и на <a href="https://vvvnik.gitlab.io/ods-project/project-guide/1/index.html">сайте</a>. Так же на сайте можно посмотреть <a href="https://vvvnik.gitlab.io/ods-project/project-guide/1/index.html#ознакомительное-видео-проекта">ознакомительное видео проекта</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub начнет брать деньги даже за локальные Actions пользователя уже с 2026 года</title>
      <link>https://tproger.ru/news/github-nachnet-brat-dengi-dazhe-za-lokalnye-actions-polzovatelya-uzhe-s-2026-goda</link>
      <comments>https://tproger.ru/news/github-nachnet-brat-dengi-dazhe-za-lokalnye-actions-polzovatelya-uzhe-s-2026-goda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-nachnet-brat-dengi-dazhe-za-lokalnye-actions-polzovatelya-uzhe-s-2026-goda</guid>
      <description><![CDATA[<p>GitHub с 2026 года начнет брать плату за self-hosted Actions в приватных репозиториях, несмотря на запуск CI на своем железе</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-nachnet-brat-dengi-dazhe-za-lokalnye-actions-polzovatelya-uzhe-s-2026-goda">GitHub начнет брать деньги даже за локальные Actions пользователя уже с 2026 года</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 17 Dec 2025 06:20:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>GitHub <a href="https://github.blog/changelog/2025-12-16-coming-soon-simpler-pricing-and-a-better-experience-for-github-actions/">объявил</a> об изменении модели оплаты GitHub Actions.</p><p>Начиная <b>с 1 марта 2026 года</b>, компания начнет взимать плату за использование <b>self-hosted runners</b> — то есть CI-джоб, которые запускаются на собственном железе пользователя, а не на инфраструктуре GitHub.</p><p>Стоимость составит <b>$0,002 за минуту</b> и будет применяться к задачам в <b>приватных репозиториях</b>.</p><p>Использование раннеров в публичных репозиториях по-прежнему останется бесплатным. Клиентов <b>GitHub Enterprise Server</b> изменения не затронут.</p><h2>Что изменится и когда</h2><p>Изменения вводятся в два этапа:</p><ul><li><b>1 января 2026 года</b> GitHub снизит цены на GitHub-hosted runners — в зависимости от типа машины, экономия может достигать <b>39%</b>.</li><li><b>1 марта 2026 года</b> начнет действовать новая плата за self-hosted runners. Эти минуты будут списываться так же, как и обычные минуты GitHub Actions. Их можно будет расходовать за счет бесплатной квоты, включенной в тариф.</li></ul><p>При этом сама квота бесплатных минут в тарифах не меняется.</p><h2>Почему GitHub берет деньги за «чужое» железо</h2><p>GitHub объясняет решение тем, что даже при запуске CI на собственных серверах пользователи активно используют облачную инфраструктуру GitHub: оркестрацию, API, логирование, безопасность и другие сервисы.</p><p>Ранее эти затраты фактически субсидировались за счет платных GitHub-hosted runners.</p><p>Новая модель, по словам компании, должна «более честно» распределять стоимость между всеми пользователями и одновременно профинансировать дальнейшее развитие GitHub Actions.</p><h2>Кого это реально затронет</h2><p>По оценке GitHub, <b>96% пользователей не увидят изменений в счете</b>. Из оставшихся 4%:</p><ul><li>у <b>85% расходы даже снизятся</b> за счет удешевления hosted runners;</li><li>у оставшихся медианный рост составит около <b>$13 в месяц</b>.</li></ul><p>Среди индивидуальных разработчиков (Free и Pro-планы), которые используют Actions только в приватных репозиториях, рост расходов затронет всего <b>0,09% пользователей</b>, при медианном увеличении менее <b>$2 в месяц</b>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Исследование: 90% кода, написанного с вайб-кодингом, содержит уязвимости</title>
      <link>https://tproger.ru/news/issledovanie--90--rewenij-s-ispolzovaniem-vajb-kodinga-soderzhat-uyazvimosti</link>
      <comments>https://tproger.ru/news/issledovanie--90--rewenij-s-ispolzovaniem-vajb-kodinga-soderzhat-uyazvimosti?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/issledovanie--90--rewenij-s-ispolzovaniem-vajb-kodinga-soderzhat-uyazvimosti</guid>
      <description><![CDATA[<p>Исследование показало, что 90% кода, созданного через вайб-кодинг, содержит уязвимости. Даже если функции проходят тесты</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/issledovanie--90--rewenij-s-ispolzovaniem-vajb-kodinga-soderzhat-uyazvimosti">Исследование: 90% кода, написанного с вайб-кодингом, содержит уязвимости</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Безопасный код]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 09 Dec 2025 06:18:16 GMT</pubDate>
      <content:encoded><![CDATA[<p>По данным недавнего опроса, 75% разработчиков так или иначе используют вайб-кодинг. А многие компании — включая Anthropic — открыто говорят, что применяют его «в проде».</p><p>Но вместе с ростом популярности подхода, возник и главный вопрос: <b>насколько безопасен код, который генерирует ИИ-агент</b>?</p><h2>Исследование показало: функционально — да, безопасно — нет</h2><p>Ученые из <i>Carnegie Mellon</i>, <i>Columbia</i> и <i>Johns Hopkins</i> <a href="https://arxiv.org/pdf/2512.03262">выпустили</a> первое крупное исследование безопасности вайб-кодинга.</p><p>Они создали собственный бенчмарк <b>SUSVIBES</b>, состоящий из <b>200 настоящих задач с GitHub-проектов</b>, где ранее были реальные уязвимости (77 видов CWE).</p><p>Каждая задача требует внедрения фичи в живой репозиторий размером в сотни тысяч строк. Это максимально приближено к реальной работе.</p><p>Далее они протестировали популярных агентов: <b>SWE-Agent</b>, <b>OpenHands</b> и <b>Claude Code</b>. Все они использовали самые свежие ИИ-модели вроде <b>Claude 4 Sonnet</b>, <b>Gemini 2.5 Pro </b>и <b>Kimi K2</b>.</p><p>Результаты оказались тревожными:</p><ul><li><b>61%</b> решений от лучшей связки (SWE-Agent + Claude 4 Sonnet) — функционально корректны.</li><li>Но только <b>10,5%</b> — безопасны.</li><li>Иными словами: около <b>90%</b> рабочего кода, который агент считает «готовым», содержит уязвимости.</li></ul><p>Аналогичная картина у всех других агентов и моделей: большинство результатов проходят функциональные тесты, но сыпятся на тестах безопасности.</p><h2>Какие уязвимости генерируют ИИ-агенты</h2><p>Исследователи обнаружили весь спектр проблем:</p><ul><li>утечки данных и неправильная обработка паролей;</li><li>XSS и небезопасные URL-редиректы;</li><li>ошибки верификации сессий;</li><li>тайминг-атаки;</li><li>отсутствие проверки входных данных.</li></ul><p>Что характерно, в реальных задачах агенты часто пишут код, который выглядит вполне логично. Но они все же упускают один-два критичных условия, создавая легко эксплуатируемые уязвимости.</p><p>На визуальных примерах в исследовании видно, что даже маленькие фрагменты вроде verify_password или URL-редиректа превращаются в брешь безопасности, если агент пропускает один шаг — например, нормализацию данных или сравнение времени выполнения.</p><h2>Вывод</h2><p>Исследователи подчеркивают: вайб-кодинг полезен для увеличения продуктивности, но <b>категорически непригоден без ручного ревью безопасности</b>.</p><p>Особенно это касается тех проектов, которые работают с данными пользователей, авторизацией, сессиями, API или любыми критичными процессами.</p><p>ИИ-агент может написать фичу, пройти тесты и выглядеть уверенно. Но с вероятностью около 80–90% там останется дыра, которая в реальной среде превратится в эксплойт.</p>]]></content:encoded>
    </item>
    <item>
      <title>Разработчик из Apple раскритиковал «Чистый код 2» — много слов, мало практической пользы</title>
      <link>https://tproger.ru/news/razrabotchik-iz-apple-raskritikoval--chistyj-kod-2----mnogo-slov--malo-prakticheskoj-polzy</link>
      <comments>https://tproger.ru/news/razrabotchik-iz-apple-raskritikoval--chistyj-kod-2----mnogo-slov--malo-prakticheskoj-polzy?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/razrabotchik-iz-apple-raskritikoval--chistyj-kod-2----mnogo-slov--malo-prakticheskoj-polzy</guid>
      <description><![CDATA[<p>Инженер Apple раскритиковал Clean Code 2 за многословие и устаревшие практики: книга стала толще, но не полезнее для современных разработчиков</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/razrabotchik-iz-apple-raskritikoval--chistyj-kod-2----mnogo-slov--malo-prakticheskoj-polzy">Разработчик из Apple раскритиковал «Чистый код 2» — много слов, мало практической пользы</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 03 Dec 2025 04:22:22 GMT</pubDate>
      <content:encoded><![CDATA[<p>Вышедшее в октябре <b>второе издание «Чистого кода»</b> вызвало бурную реакцию разработчиков.</p><p>Одна из самых <b>жестких рецензий</b> <a href="https://bugzmanov.github.io/cleancode-critique/clean_code_second_edition_review.html">пришла</a> от инженера Apple — <b>Рафаэля Багманова</b>. Он заявил, что книга стала «толще, но не умнее». Больше отвлеченных рассуждений, повторов и риторики, а вот <b>практической пользы — меньше</b>.</p><p>По его словам, обновленная версия ощущается как смесь Clean Code, Clean Coder, Clean Architecture и блог-постов Роберта Мартина, но без прежней фокусировки.</p><p>При этом сам <b>стиль написания кода почти не изменился</b>, а многие проблемы первого издания <b>перекочевали в новое без правок</b>.</p><h2>«Чрезмерные мини-функции» и странные абстракции</h2><p>Главная претензия Багманова — <b>навязчивый стиль Tiny Functions</b>: функции с одним параметром, длинные имена, множество маленьких методов, вызванных ради избежания комментариев.</p><p>Автор критики приводит пример разбора римских чисел: в книге Мартин <b>превращает простую задачу в набор связанных методов и полей класса</b>. Это усложняет код, а не делает его чище.</p><p>Он отдельно подчеркнул, что такой стиль легко узнаваем, но это <b>не комплимент</b>. В примерах «Чистого кода» <b>создается избыточная структура</b>, которую сложнее читать, тестировать и поддерживать.</p><h2>Слабая работа с производительностью и моделированием</h2><p>Рафаэль Багманов также отметил, что Мартин игнорирует ключевые аспекты разработки:</p><ul><li><b>производительность</b> падает из-за десятков мелких методов и постоянных аллокаций;</li><li><b>тесты замедляются</b> из-за передачи данных через поля объекта;</li><li><b>моделирование домена</b> уступает место механическому применению SOLID.</li></ul><p>Особенно досталось примеру с системой аренды помещений: попытка заменить switch на полиморфизм приводит к интерфейсу, который смешивает цену, налоги и скидки в одной сущности:</p><p>В реальных системах <b>так не работает</b> — налоговые правила зависят от региона, периода и категории товара, а не от «класса предмета».</p><h2>Комментарии: редкие хорошие примеры и странная позиция</h2><p>Несмотря на то, что Мартин снова заявляет, что комментарии — «признак провала», книга почти не показывает хороших примеров того, как писать нужные комментарии.</p><p>Инженер Apple подчеркивает: <b>в реальном мире комментарии — не зло, а инструмент</b>. И хорошую мысль проще объяснить текстом, чем ломать архитектуру ради самодокументируемости.</p><h2>Итог: книга стала объемнее, но не глубже</h2><p>В итоге Багманов пришел к выводу, что второе издание «Чистого кода» <b>скорее разочаровывает</b>. Оно наследует стиль, который не подходит современным языкам и практикам, усиливает слабые стороны первого издания и добавляет многословие без реальных улучшений.</p><p>Для инженеров, которые ищут современные советы по дизайну, сопровождению и архитектуре, книга в 2025 году выглядит устаревшей. <b>Но что хуже всего, вводящей новичков в заблуждение</b>.</p>]]></content:encoded>
    </item>
    <item>
      <title>T-строки в Python: новый способ форматирования строк</title>
      <link>https://tproger.ru/articles/t-stroki-v-python--novyj-sposob-formatirovaniya-strok</link>
      <comments>https://tproger.ru/articles/t-stroki-v-python--novyj-sposob-formatirovaniya-strok?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Валерия Турчак]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/t-stroki-v-python--novyj-sposob-formatirovaniya-strok</guid>
      <description><![CDATA[<p>Разбираемся, зачем они нужны и когда их использовать</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/t-stroki-v-python--novyj-sposob-formatirovaniya-strok">T-строки в Python: новый способ форматирования строк</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 02 Dec 2025 10:14:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Python постоянно развивает инструменты для работы со строками. В версии 3.14 появился новый синтаксис — t-строки. Разбираемся, зачем они нужны и когда их использовать.</p><p>Эта статья написана с помощью сервис . Исходник — <a href="https://www.pythonmorsels.com/t-strings-in-python/">видео и гайд про новые t-строки в Python 3.14.</a></p><h2>Эволюция форматирования строк в Python</h2><h3>Процентный стиль (%) — с самого начала</h3><p>Python умел форматировать строки через процент с первых версий:</p><h3>Класс Template — Python 2.4</h3><p>В модуле string появился альтернативный способ:</p><h3>Метод format() — Python 2.6</h3><p>Форматирование стало компактнее:</p><h3>F-строки — Python 3.6</h3><p>Этот синтаксис быстро стал стандартом де-факто:</p><h3>T-строки — Python 3.14</h3><p>Новый инструмент для отложенной интерполяции:</p><h2>Когда использовать t-строки</h2><h3>Для разработчиков приложений</h3><p>Если вы пишете прикладной код, t-строки вам скорее всего не понадобятся прямо сейчас. Применяйте их только когда библиотека, которую вы используете, явно требует передать t-строку.</p><h3>Для авторов библиотек</h3><p>T-строки полезны при разработке библиотек, где пользователям нужна отложенная интерполяция. Типичные сценарии:</p><ul><li>Экранирование SQL-запросов перед выполнением</li><li>Обработка HTML перед рендерингом</li><li>Работа с регулярными выражениями</li><li>Предварительная обработка данных перед объединением в строку</li><li>Отложенная интерполяция (как в модуле logging)</li></ul><h3>Отличия f-строк от t-строк</h3><p>Ключевое различие: f-строки выполняют интерполяцию немедленно и возвращают готовую строку, t-строки возвращают объект Template с отложенной интерполяцией.</p><h4>Проблема, которую не решают f-строки</h4><p>Рассмотрим функцию dedent из модуля textwrap, которая удаляет общие отступы из текста:</p><p>Результат:</p><p>Функция корректно убирает общие отступы, но сохраняет относительные:</p><p>Результат:</p><h3>Где f-строки создают проблему</h3><p>Возьмём многострочный код:</p><p>Попробуем вставить его в f-строку и передать в dedent:</p><p>Получаем некорректный результат:</p><p>Первая строка кода имеет отступ, остальные — нет. Вся выходная строка обработана неправильно.</p><h3>Причина проблемы</h3><p>F-строка выполняет интерполяцию до того, как результат попадает в dedent. К этому моменту функция не может понять, как выглядела исходная строка до подстановки значений.</p><p>F-строка взяла строку без общих отступов (code) и поместила её внутрь строки с отступами. Когда итоговая строка попала в dedent, функция не смогла корректно определить, что нужно было сначала добавить отступы к подставляемому значению, а потом убрать общие отступы.</p><p>Функция dedent не может посмотреть историю и понять структуру исходной f-строки.</p><h2>Как работают t-строки</h2><h3>T-строки возвращают объекты Template</h3><p>F-строка возвращает готовую строку:</p><p>T-строка возвращает объект Template:</p><p>Итерация по объекту Template даёт смесь строковых фрагментов и объектов интерполяции:</p><h4>Применение t-строк</h4><p>Объект Template позволяет библиотекам предварительно обрабатывать интерполируемые части перед финальной сборкой строки.</p><h2>Решение проблемы dedent с t-строками</h2><p>Используем t-строку вместо f-строки:</p><p>Корректный результат:</p><p>Версия dedent, работающая с t-строками, видит, что подставляемое значение имело относительные отступы внутри более крупной строки, но само содержимое не было с отступами. Функция корректно применяет отступы к подставляемому значению перед удалением общих отступов у всей строки.</p><h2>Реализация dedent для t-строк</h2><p>Кастомная версия dedent для работы с t-строками:</p><p>Функция выполняет следующие операции:</p><ol><li>Использует стандартный dedent из модуля textwrap</li><li>Обрабатывает каждое интерполируемое значение в зависимости от его содержимого</li><li>Учитывает позицию значения внутри более крупной строки</li><li>Корректно применяет отступы перед финальной обработкой</li></ol><p>Эта реализация доступна в виде библиотеки better-dedent в индексе пакетов Python:</p><p>Автор предупреждает, что библиотека может содержать баги, поэтому сообщайте о найденных проблемах в репозитории проекта.</p><h3>Вывод по t-строкам: нужны или нет</h3><h4>Писать t-строки просто</h4><p>Синтаксис t-строки идентичен f-строке, меняется только префикс:</p><h4>Работать с Template сложнее</h4><p>Работа с объектом Template, который возвращает t-строка, требует понимания его структуры: нужно уметь итерироваться по частям и обрабатывать интерполяции.</p><p>В большинстве случаев вы не будете напрямую работать с t-строками и объектами Template в повседневном коде. Вы будете передавать их в библиотеки, которые специально разработаны для приёма t-строк.</p><p>Если библиотека поддерживает t-строки — передайте ей t-строку. Всё остальное библиотека обработает сама.</p><h4>Перспективы t-строк</h4><p>Python 3.14 вышел недавно, поэтому примеров использования t-строк в реальных проектах пока немного. Создатели t-строк ведут список <a href="https://github.com/t-strings/awesome-t-strings">awesome t-string</a> для тех, кто хочет следить за развитием экосистемы.</p><p>Следите за обновлениями библиотек, которыми вы пользуетесь — возможно, скоро они начнут поддерживать t-строки для более гибкой работы со строками.</p>]]></content:encoded>
    </item>
    <item>
      <title>Хакеры внедрили вирусы в почти 500 npm-пакетов. Под удар попали Postman, PostHog, AsynAPI и другие</title>
      <link>https://tproger.ru/news/hakery-vnedrili-virusy-v-pochti-500-npm-paketov--pod-udar-popali-postman--posthog--asynapi-i-drugie</link>
      <comments>https://tproger.ru/news/hakery-vnedrili-virusy-v-pochti-500-npm-paketov--pod-udar-popali-postman--posthog--asynapi-i-drugie?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/hakery-vnedrili-virusy-v-pochti-500-npm-paketov--pod-udar-popali-postman--posthog--asynapi-i-drugie</guid>
      <description><![CDATA[<p>Хакеры заразили почти 500 npm-пакетов червем Shai Hulud: под удар попали Postman, PostHog, AsyncAPI и другие проекты, украдены ключи и токены</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/hakery-vnedrili-virusy-v-pochti-500-npm-paketov--pod-udar-popali-postman--posthog--asynapi-i-drugie">Хакеры внедрили вирусы в почти 500 npm-пакетов. Под удар попали Postman, PostHog, AsynAPI и другие</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 25 Nov 2025 06:36:33 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>24 ноября</b> исследователи <a href="https://www.aikido.dev/blog/shai-hulud-strikes-again-hitting-zapier-ensdomains">зафиксировали</a> <b>новую волну атаки Shai Hulud</b> — самораспространяющегося npm-червя.</p><p>Злоумышленники <b>внедрили вредоносный код в 492 пакета</b>, суммарно набирающих <b>более 132 млн загрузок в месяц</b>. Если такой пакет устанавливает разработчик, вредонос запускается еще до завершения установки и получает доступ к его среде разработки.</p><p>Отметим, что текущая кампания стала «вторым пришествием» Shai Hulud. Злоумышленники приурочили ее к декабрьской блокировке старых npm-токенов. Атакующие явно рассчитывали успеть нанести максимальный урон до обновления безопасности.</p><h2>Как работает новая версия Shai Hulud</h2><p>По сравнению с атакой в сентябре, вредонос стал агрессивнее. И заметно опаснее:</p><ul><li>теперь он <b>устанавливает Bun</b> и запускает основную вредоносную логику через bun_environment.js;</li><li>создает <b>случайный GitHub-репозиторий</b> и складывает туда украденные токены и ключи;</li><li>пытается заразить <b>до 100 пакетов</b>, а не 20, как раньше;</li><li>если не удается авторизоваться в GitHub или npm, вредонос <b>стирает все файлы в домашней директории пользователя</b>.</li></ul><p>Внутри зараженного пакета находится setup_bun.js, который либо запускает вредонос напрямую, либо подготавливает окружение, чтобы тот мог работать.</p><p>В некоторых скомпрометированных пакетах второй файл отсутствует — исследователи считают это ошибкой самих атакующих, которая частично снизила масштаб атаки.</p><h2>Кто пострадал</h2><p>Под удар попали проекты <b>AsyncAPI</b>, <b>PostHog</b>, <b>Postman</b>, <b>Zapier</b>, <b>ENS </b>и <b>десятки независимых разработчиков</b>. Первые зараженные пакеты появились примерно <b>в 6 утра по Москве</b>, после чего атака быстро распространилась на крупные экосистемы.</p><p>Исследователи обнаружили также скомпрометированную ветку в репозитории <b>AsyncAPI CLI</b> — вероятно, заражение отдельных проектов шло через те же методы, что и в предыдущей атаке на Nx.</p><h2>Что похищают злоумышленники</h2><p>Вредонос автоматически запускает TruffleHog и ищет в системе:</p><ul><li>ключи GitHub и npm,</li><li>токены облаков и CI/CD,</li><li>пароли, API-ключи и любые другие секреты.</li></ul><p>Если атакующие получат токены для публикации npm-пакетов или доступа к репозиториям, они могут продолжить цепочку атак и заражать новые проекты.</p><h2>Что делать командам безопасности</h2><p>Пока специалисты продолжают анализировать атаку, есть ряд мер, которые можно предпринять уже сейчас:</p><ul><li>проверить все зависимости, особенно пакеты AsyncAPI, PostHog, Postman, Zapier, ENS;</li><li>срочно ротировать GitHub, npm и облачные ключи, использовавшиеся в процессе разработки или CI;</li><li>искать подозрительные GitHub-репозитории с пометкой “Sha1-Hulud: The Second Coming”;</li><li>максимально ограничить или отключить postinstall-скрипты в CI;</li><li>зафиксировать версии зависимостей и включить обязательную MFA на npm и GitHub;</li><li>использовать инструменты фильтрации вредоносных пакетов в цепочке поставок.</li></ul><p>Атака продолжает развиваться — следим за обновлениями.</p>]]></content:encoded>
    </item>
    <item>
      <title>Создатель Linux поддержал вайб-кодинг, назвав его «отличным способом войти в IT»</title>
      <link>https://tproger.ru/news/sozdatel-linux-podderzhal-vajb-koding--nazvav-ego--otlichnym-sposobom-vojti-v-it-</link>
      <comments>https://tproger.ru/news/sozdatel-linux-podderzhal-vajb-koding--nazvav-ego--otlichnym-sposobom-vojti-v-it-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/sozdatel-linux-podderzhal-vajb-koding--nazvav-ego--otlichnym-sposobom-vojti-v-it-</guid>
      <description><![CDATA[<p>Линус Торвальдс поддержал вайб-кодинг как легкий вход в IT, но предупредил: для реальных проектов это плохо подходит и усложняет поддержку</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/sozdatel-linux-podderzhal-vajb-koding--nazvav-ego--otlichnym-sposobom-vojti-v-it-">Создатель Linux поддержал вайб-кодинг, назвав его «отличным способом войти в IT»</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Компиляторы]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[NVIDIA]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 20 Nov 2025 06:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Линус Торвальдс</b> неожиданно <a href="https://www.theregister.com/2025/11/18/linus_torvalds_vibe_coding/">высказался</a> <b>в поддержку вайб-кодинга</b>. Но только как способа входа в профессию, а не как подхода к разработке реального продукта.</p><p>Об этом он рассказал в интервью на <b>Open Source Summit</b> в Сеуле.</p><h2>«Я уже 20 лет не программист»</h2><p>Торвальдс признался, что своей основной задачей <b>давно</b> <b>не считает написание кода</b>:</p><blockquote>«Около 20 последних лет я не программист. Я смотрю на Git со стороны, а в ядре моя роль — соглашаться или отказывать».</blockquote><p>Он отметил, что все чаще приходится «говорить да» новым идеям, несмотря на сопротивление старых мейнтейнеров. Это можно заметить, например, в вопросе <b>интеграции Rust в ядро Linux</b>.</p><h2>Что он думает об ИИ и разработке</h2><p>Несмотря на то, что сам <b>Линус не пользуется ИИ-ассистентами</b>, он не исключает, что такие инструменты могут пригодиться в ядре. Основная проблема ИИ сейчас, по его словам — не код, а инфраструктура:</p><blockquote>«ИИ-краулеры сильно захламляют наши ресурсы, притаскивают баги и репорты, которых не существует».</blockquote><p>При этом <b>Торвальдс позитивно оценивает влияние ИИ-бума на индустрию</b>: из-за него NVIDIA стала «значительно более хорошим игроком» в Linux-сообществе.</p><h2>А что с вайб-кодингом?</h2><p>Именно здесь Линус удивил больше всего. Он сказал, что относится к вайб-кодингу <b>«довольно позитивно»</b>, потому что он:</p><ul><li>облегчает вход в программирование для новичков;</li><li>позволяет увидеть быстрый результат;</li><li>снижает технический порог для тех, кто раньше не мог «заставить компьютер что-то делать».</li></ul><p>Но использовать это в реальных проектах — гиблая идея:</p><blockquote>«Это может быть ужасным решением с точки зрения поддержки».</blockquote><p>По мнению Торвальдса, <b>вайб-кодинг — отличная «точка входа»</b>, но <b>плохой фундамент</b> для сложных систем вроде ядра Linux.</p><h2>Вердикт Линуса</h2><p>Он видит ИИ как обычный инструмент — как когда-то компиляторы, которые избавили разработчиков от необходимости писать код ассемблера вручную:</p><blockquote>«ИИ не убьет профессию. Как и компиляторы, он просто повысит продуктивность».</blockquote>]]></content:encoded>
    </item>
    <item>
      <title>Вышла Google Gemini 3 — апдейт, который в компании называют шагом к AGI</title>
      <link>https://tproger.ru/news/google-zapustila-gemini-3---apdejt--kotoryj-v-kompanii-nazyvayut-wagom-k-agi</link>
      <comments>https://tproger.ru/news/google-zapustila-gemini-3---apdejt--kotoryj-v-kompanii-nazyvayut-wagom-k-agi?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/google-zapustila-gemini-3---apdejt--kotoryj-v-kompanii-nazyvayut-wagom-k-agi</guid>
      <description><![CDATA[<p>Google представила Gemini 3 — новое поколение ИИ с усиленной мультимодальностью, логикой и агентностью, которое компания называет шагом к AGI</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/google-zapustila-gemini-3---apdejt--kotoryj-v-kompanii-nazyvayut-wagom-k-agi">Вышла Google Gemini 3 — апдейт, который в компании называют шагом к AGI</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[JetBrains]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 19 Nov 2025 04:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Google</b> <a href="https://blog.google/products/gemini/gemini-3">представила</a> <b>Gemini 3</b> — новое поколение своей <b>флагманской модели</b>, которое в компании прямо называют «большим шагом по пути к AGI».</p><p>Модель уже встраивают почти во все ключевые продукты Google — <b>от поиска до инструментов для разработчиков</b>.</p><h2>Что такое Gemini 3</h2><p><b>Gemini 3</b> представляет из себя новое семейство моделей. Основным флагманом в нем выступает <b>Gemini 3 Pro</b>, а для сложных задач появится отдельный режим <b>Gemini 3 Deep Think</b>.</p><p>По сути, это эволюция сразу в трех направлениях:</p><ul><li><b>Мультимодальность</b> — текст, код, картинки, видео, аудио в одном стеке.</li><li><b>Reasoning</b> и <b>«глубокое мышление»</b> — лучше решает сложные задачи по науке, математике и планированию.</li><li><b>Агентность</b> — модель умеет не только отвечать, но и выполнять цепочки действий: работать с браузером, почтой, кодом.</li></ul><p>Google отдельно подчеркивает: при создании Gemini 3 авторы метили не в «просто чат для общения», а в «ИИ, который помогает доводить любую идею до реализации».</p><h2>Чем Gemini 3 отличается от 2.5</h2><p>По заявлениям Google, Gemini 3 Pro:</p><ul><li>заметно обгоняет Gemini 2.5 Pro в большинстве бенчмарков по математике, логике, точности фактов;</li><li>лучше понимает контекст и намерение — нужно меньше «танцев с промптами»;</li><li>умеет генерировать код для сложных визуализаций, интерфейсов и 3D-сцен;</li><li>работает как «thought partner» — пытается сокращать воду и говорить по делу, а не льстить.</li></ul><p>Отдельный режим <b>Gemini 3 Deep Think</b> дает еще больший прирост в задачах на логику и новизну, но пока доступен только безопасностным тестерам. Позже появится и у подписчиков Google AI Ultra.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2025-11-18/4d7a5a4f-b3bd-40d1-9ada-fa08436ba526.jpeg" alt="" /></figure><h2>Где уже можно попробовать</h2><p>Gemini 3 начинают раскатывать сразу «в масштабах Google»:</p><ul><li><b>Поиск (AI Mode в Search)</b> — генерируемые ответы, визуальные раскладки, интерактивные элементы, симуляции.</li><li><b>Приложение Gemini</b> — для обычных пользователей и подписчиков Google AI Pro/Ultra.</li><li><b>Для разработчиков:</b> Google AI Studio, Vertex AI, Gemini CLI, новый агентный IDE-платформер <b>Google Antigravity</b>.</li><li><b>Интеграции</b>: Cursor, GitHub, JetBrains, Replit и другие сторонние инструменты.</li></ul><h2>Google Antigravity: агент как напарник, а не просто советчик</h2><p>Отдельно Google показала <b>Antigravity</b> — «agent-first» платформу для разработки:</p><ul><li>агент получает доступ к редактору, терминалу и браузеру;</li><li>может сам планировать и выполнять end-to-end задачи (например, собрать приложение, проверить, запустить, поправить баги);</li><li>под капотом — Gemini 3 + специализированная модель для управления компьютером и модель для работы с картинками.</li></ul><p>Идея простая: разработчик формулирует цель, а не последовательность команд.</p><h2>Безопасность и «шаг к AGI»</h2><p>Google утверждает, что Gemini 3 — их «самая проверенная» и «самая безопасная» модель:</p><p>При этом в компании также заявляются: <b>Gemini 3 это крупный шаг к более общему интеллекту</b>, а не просто очередная версия чат-бота.</p>]]></content:encoded>
    </item>
    <item>
      <title>Google представила Code Wiki — ИИ, пишущий и обновляющий документацию для любых GitHub-репозиториев</title>
      <link>https://tproger.ru/news/google-predstavila-code-wiki---ii--piwushhij-i-obnovlyayushhij-dokumentaciyu-dlya-lyubyh-github-repozitoriev</link>
      <comments>https://tproger.ru/news/google-predstavila-code-wiki---ii--piwushhij-i-obnovlyayushhij-dokumentaciyu-dlya-lyubyh-github-repozitoriev?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/google-predstavila-code-wiki---ii--piwushhij-i-obnovlyayushhij-dokumentaciyu-dlya-lyubyh-github-repozitoriev</guid>
      <description><![CDATA[<p>Google запустила Code Wiki — ИИ, который генерирует и обновляет документацию GitHub-репозиториев, связывает её с кодом и ускоряет понимание проектов</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/google-predstavila-code-wiki---ii--piwushhij-i-obnovlyayushhij-dokumentaciyu-dlya-lyubyh-github-repozitoriev">Google представила Code Wiki — ИИ, пишущий и обновляющий документацию для любых GitHub-репозиториев</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 17 Nov 2025 05:50:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Google <a href="https://codewiki.google/">запустила</a> <b>Code Wiki</b> — сервис, который <b>автоматически генерирует</b> живую, постоянно обновляемую <b>документацию</b> для открытых GitHub-репозиториев.</p><p>Компания называет проект попыткой решить одну из самых дорогих и медленных задач в разработке — <b>необходимость разбираться в чужом коде вручную</b>.</p><h2>Что делает Code Wiki</h2><p>Сервис сканирует весь репозиторий, строит структурированную wiki-документацию и перегенерирует ее после каждого коммита.</p><p>Таким образом, мы получаем не просто статичный README и не набор заметок. Локальная «Википедия по проекту» <b>остается синхронизированной</b> с кодовой базой <b>всегда</b>. Google подчеркивает несколько ключевых возможностей:</p><ul><li><b>Автоматическая документация.</b> Code Wiki описывает архитектуру, модули, классы, функции. Причем делает это регулярно, без участия разработчика.</li><li>Глубокий контекст. Встроенный чат на базе Gemini использует сгенерированную wiki как базу знаний. В итоге мы получаем не «общий» ИИ, а агента, который знает репозиторий целиком.</li><li><b>Навигация по коду.</b> Все элементы документации связаны гиперссылками с исходниками — можно сразу перейти от объяснения к конкретной строчке реализации.</li><li><b>Диаграммы.</b> Сервис автоматически рисует актуальные архитектурные, sequence- и class-диаграммы, которые меняются вместе с кодом.</li></ul><p>По задумке Google, новая система должна <b>сократить время входа в проект</b>: новичок сможет ориентироваться в большом репозитории <b>в первые часы</b>, а <b>не через неделю</b>.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2025-11-17/9d8cc7dc-157f-4645-8bf9-ae361ac3519d.jpeg" alt="" /></figure><h2>Что дальше</h2><p>Пока Code Wiki работает только <b>с публичными проектами</b>. Но Google уже делает CLI-расширение для Gemini, которое позволит генерировать документацию для закрытых, внутренних кодовых баз — <b>локально и без передачи данных в облако</b>.</p><p>Для компаний это может стать инструментом для работы с legacy-кодом: документация будет обновляться автоматически, даже если исходные авторы давно уволились.</p><h2>Зачем все это</h2><p>Google утверждает, что <b>эпоха написанных вручную устаревающих документов заканчивается</b>. Разработчики все чаще пишут код с ИИ-помощниками, но все еще тратят огромные усилия на чтение чужого.</p><p>Code Wiki должен закрыть этот пробел и превратить понимание кода в операцию, которая занимает минуты. Сервис <b>уже работает</b> в виде публичного превью на <a href="http://codewiki.google">codewiki.google</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Представлен Chad IDE — смотри TikTok и свайпай Tinder, пока ИИ пишет код</title>
      <link>https://tproger.ru/news/predstavlen-chad-ide---smotri-tiktok-i-svajpaj-tinder--poka-ii-piwet-kod</link>
      <comments>https://tproger.ru/news/predstavlen-chad-ide---smotri-tiktok-i-svajpaj-tinder--poka-ii-piwet-kod?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/predstavlen-chad-ide---smotri-tiktok-i-svajpaj-tinder--poka-ii-piwet-kod</guid>
      <description><![CDATA[<p>Chad IDE — среда, где можно смотреть TikTok и свайпать Tinder, пока ИИ пишет код. Разработку без скуки авторы зовут новым форматом</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/predstavlen-chad-ide---smotri-tiktok-i-svajpaj-tinder--poka-ii-piwet-kod">Представлен Chad IDE — смотри TikTok и свайпай Tinder, пока ИИ пишет код</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[YouTube]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[TikTok]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 12 Nov 2025 13:11:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>В сети <a href="https://www.cladlabs.ai/blog/introducing-clad-labs">набирает</a> популярность шуточная (или не очень) среда разработки <b>Chad IDE</b>. Авторы проекта позиционируют его как «первую в мире IDE, где скучать невозможно».</p><p>Пока нейросеть пишет код, программист может смотреть TikTok, листать Tinder или играть в мини-игры.</p><h2>Проблема, о которой никто не говорил</h2><p>Создатели Chad IDE заявляют, что современные инструменты вроде GitHub Copilot породили новую форму «кризиса продуктивности». Мол пока ИИ пишет код, разработчик вынужден просто ждать.</p><p>Исследование команды показало, что <b>87% инженеров в этот момент тянутся к телефону</b>. И, по данным самих авторов, теряют по 5–10 минут на пролистывание соцсетей после каждой генерации.</p><p>Так появился концепт «engagement-driven development» — разработки без скуки.</p><h2>Как это работает</h2><p>Chad IDE добавляет в окно разработки развлечения «с пользой для фокуса». Ключевая идея — не дать разработчику покинуть IDE, но при этом удержать внимание в контексте проекта.</p><h3>Основные функции</h3><ul><li><b>Active Generation Monitoring</b> — визуализирует процесс генерации кода, добавляя анимации и контекстные подсказки.</li><li><b>Micro-Interactions</b> — легкие интерактивные элементы, которые не мешают, но отвлекают от телефона.</li><li><b>Context Preservation</b> — IDE «напоминает», над чем вы работаете, даже если вы смотрите видео.</li></ul><h2>Интеграции</h2><p>Chad IDE поддерживает сервисы, которые обычно отвлекают. Теперь они используются «для концентрации»:</p><ul><li><b>TikTok и *Instagram Reels</b> — вертикальные видео прямо в редакторе, автопауза при фокусе на коде.</li><li><b>YouTube Shorts</b> — подборка видео о программировании.</li><li><b>Tinder</b> — свайпы с «кодовыми» айсбрейкерами для разработчиков.</li><li><b>Мини-игры</b> — казуальные игры во время компиляции.</li></ul><p>Авторы уверяют, что эти функции не мешают, а наоборот — предотвращают контекстные переключения.</p><h2>Эффект: «меньше скуки — больше кода»</h2><p>По данным внутреннего тестирования:</p><ul><li>количество отвлечений снизилось на <b>43%</b>;</li><li>время, потерянное на телефон, сократилось на <b>2,3 часа в день</b>;</li><li>продолжительность «состояния потока» выросла на <b>67%</b>;</li><li>а раздражение из-за долгих генераций — на <b>89% меньше</b>.</li></ul><p>Один из тестировщиков из *Meta назвал IDE «фиджет-спиннером для мозга, который держит тебя в контексте кода».</p><p>*Компания Meta и ее продукты признаны экстремистскими, их деятельность запрещена на территории РФ</p>]]></content:encoded>
    </item>
    <item>
      <title>Как подключить VSCode к GitLab, Docker, Jupyter</title>
      <link>https://tproger.ru/articles/kak-podklyuchit-vscode-k-gitlab--docker--jupyter</link>
      <comments>https://tproger.ru/articles/kak-podklyuchit-vscode-k-gitlab--docker--jupyter?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вадим Егорцев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-podklyuchit-vscode-k-gitlab--docker--jupyter</guid>
      <description><![CDATA[<p>Пошаговая инструкция по интеграции VSCode с GitLab, Docker и Jupyter. Как получить токен доступа, настроить Dev Container, выбрать ядро для ноутбука и объединить все инструменты разработки в одном редакторе.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-podklyuchit-vscode-k-gitlab--docker--jupyter">Как подключить VSCode к GitLab, Docker, Jupyter</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 12 Nov 2025 10:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчики каждый день открывают VSCode и начинают писать код. Но редактор сам по себе — это просто текстовый блокнот с подсветкой синтаксиса.</p><p>Продуктивность разработчика повышается, когда к VSCode подключены инструменты для командной работы, контейнеризации и анализа данных. В статье по шагам разобрали, как интегрировать VSCode с GitLab, Docker и Jupyter.</p><h2>Зачем всё это подключать</h2><p>VSCode из коробки умеет работать с <b>Git</b>. Но когда ваш репозиторий лежит на GitLab, хочется создавать merge request прямо из редактора, просматривать pipeline, работать с issues.</p><p><b>Docker </b>решает проблему «у меня работает, а у тебя нет». Вы пишете код в контейнере с одними версиями библиотек, и любой член команды запустит точно такое же окружение.</p><p><b>Jupyter </b>традиционно запускают в браузере. Но переключаться между браузером и редактором неудобно. VSCode умеет работать напрямую — редактируете код, запускаете ячейки, смотрите графики в одном окне.</p><h2>Как подключить VSCode к GitLab</h2><h2>Шаг 1. Устанавливаем расширение</h2><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-11-05/0971c3c4-ccd5-4c1a-8642-2895bb77ba7d.jpg" alt="" /></figure><p>Откройте VSCode и нажмите Ctrl+Shift+X. В поиске введите «GitLab Workflow». Установите официальное расширение. После установки в левой панели появится иконка GitLab.</p><h2>Шаг 2. Получаем токен доступа</h2><p>Расширению нужен способ общаться с вашим GitLab-сервером. Для этого создадим персональный токен:</p><ol><li>Зайдите в GitLab через браузер.</li><li>Кликните на аватар &gt;&gt; Settings &gt;&gt; Access Tokens.</li><li>Придумайте название токена.</li><li>Выберите срок действия.</li><li>Отметьте галочками права доступа: api, read_user, read_repository, write_repository.</li><li>Нажмите «Create personal access token».</li><li>Скопируйте токен — он покажется только один раз.</li></ol><h2>Шаг 3. Настраиваем расширение</h2><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-11-05/b05bc74a-9bf9-4150-b228-b8065918ca18.jpg" alt="" /></figure><p>Вернитесь в VSCode. Нажмите Ctrl+Shift+P и введите «GitLab: Add Account». Расширение попросит два параметра:</p><ul><li><b>GitLab instance URL</b> — адрес вашего GitLab (например, https://gitlab.com или адрес корпоративного сервера).</li><li><b>Personal Access Token</b> — токен, который только что создали.</li></ul><p>Вставьте токен и нажмите Enter. Если всё правильно, в статус-баре внизу появится ваше имя пользователя GitLab.</p><h2>Шаг 4. Работаем с проектом</h2><p>Попробуем клонировать проект. Нажмите Ctrl+Shift+P и выберите «GitLab: Clone from GitLab». Расширение покажет список доступных проектов. Выберите нужный, укажите папку для клонирования.</p><p>Теперь вам доступны функции Git:</p><ul><li><b>Pipeline </b>— в боковой панели GitLab видны все запущенные сборки, их статусы и логи.</li><li><b>Issues </b>— создавайте, редактируйте и закрывайте задачи прямо из редактора.</li><li><b>Merge requests</b> — посмотрите список MR, оставьте комментарии к коду, одобрите изменения.</li><li><b>Snippets </b>— сохраняйте фрагменты кода для повторного использования.</li></ul><h2>Как подключить VSCode к Docker</h2><p>Редактор умеет запускать код прямо внутри контейнера. Вы редактируете файлы, а выполняются они в изолированной среде с выбранными настройками.</p><h2>Шаг 1. Подготовка</h2><p>Установите Docker Desktop с <a href="https://www.docker.com/products/docker-desktop/">официального сайта</a>. После установки убедитесь, что Docker запущен — в системном трее должна появиться иконка кита.</p><p>В VSCode установите два расширения:</p><ul><li>Docker.</li><li>Dev Containers.</li></ul><h2>Шаг 2. Создаём Dockerfile</h2><p>В корне проекта создайте файл Dockerfile. Пример для Python-проекта:</p><p>Этот файл говорит Docker:</p><ol><li>Возьми базовый образ Python 3.11.</li><li>Создай рабочую директорию /app.</li><li>Скопируй и установи зависимости.</li><li>Скопируй весь код проекта.</li><li>При запуске выполни команду python main.py.</li></ol><h2>Шаг 3. Настраиваем Dev Container</h2><p>Создайте папку .devcontainer в корне проекта. Внутри создайте файл devcontainer.json:</p><p>Конфигурация использует ваш Dockerfile для сборки контейнера. Она автоматически устанавливает Python-расширения внутри контейнера, пробрасывает порт 8000 (если у вас веб-приложение) и выполняет команду после создания контейнера.</p><h2>Шаг 4. Запускаем разработку в контейнере</h2><p>Нажмите Ctrl+Shift+P и выберите «Dev Containers: Reopen in Container». Редактор соберёт Docker-образ по вашему Dockerfile, запустит контейнер, подключится к нему и откроет ваш проект уже внутри контейнера.</p><p>Теперь весь код выполняется в изолированной среде. Терминал в VSCode работает внутри контейнера. Расширения устанавливаются в контейнер, отладчик запускает код там же.</p><h2>Как подключить VSCode к Jupyter</h2><p>В классическом интерфейсе нет нормального автодополнения кода, сложно работать с Git, неудобно рефакторить код и нет полноценной отладки. Плагины VSCode решают эти проблемы.</p><h2>Шаг 1. Установка</h2><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-11-05/eb48ea48-285c-4f04-90c2-e20932174fe9.jpg" alt="" /></figure><p>Установите расширение «Jupyter» от Microsoft. Оно автоматически подтянет все необходимые зависимости.</p><p>В терминале установите Jupyter и ipykernel:</p><h2>Шаг 2. Создаём первый ноутбук</h2><p>Создайте файл с расширением .ipynb или нажмите Ctrl+Shift+P &gt;&gt; «Create: New Jupyter Notebook».</p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-11-05/f956c803-cb87-4a4e-b849-7f4b956fb2e8.jpg" alt="" /></figure><p>VSCode откроет интерфейс ноутбука. Вверху вы увидите панель инструментов с выбором ядра, кнопки запуска и добавления ячеек.</p><h2>Шаг 3. Выбираем ядро</h2><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-11-05/d66667d6-f595-494f-a0ef-a9480b1b9da8.jpg" alt="" /></figure><p>Кликните на «Select Kernel» в правом верхнем углу. VSCode покажет список доступных интерпретаторов:</p><ul><li>Локальные Python-окружения.</li><li>Виртуальные окружения (venv, conda).</li><li>Docker-контейнеры (если настроены).</li><li>Удалённые Jupyter-серверы.</li></ul><p>Выберите нужное окружение. VSCode запомнит выбор для этого ноутбука.</p><h2>Шаг 4. Пишем и выполняем код</h2><p>В ячейке напишите код:</p><p>Нажмите Shift+Enter для выполнения ячейки. График отобразится прямо под кодом.</p><p>Для Python-файлов можно включить интерактивный режим. Добавьте комментарий <i># %%</i> в .py файл:</p><p>VSCode покажет кнопки «Run Cell» над каждым блоком. Теперь можно выполнять код частям.</p><h2>Что в итоге</h2><p>Первая настройка VSCode с GitLab, Docker и Jupyter занимает 30-40 минут. В итоге вы получаете единое рабочее пространство для ваших задач разработки.</p><p>Начните с GitLab и научитесь создавать merge requests из редактора. Потом добавьте Docker для одного проекта. Когда освоитесь, подключите Jupyter для работы с данными. Инструменты решают разные задачи, а VSCode объединяет их функции в одном интерфейсе.</p><p>Возьмите проект и последовательно подключите каждый инструмент. Через неделю удивитесь, как раньше работали без этой связки. Код пишется быстрее, ошибок меньше, а переключений между окнами почти нет.</p><p><i>Если что-то непонятно или не получается настроить — пишите в комментариях, разберёмся вместе!</i></p>]]></content:encoded>
    </item>
    <item>
      <title>OpenAI массово нанимает «super junior» — джунов без опыта разработки, но с навыками работы с ИИ</title>
      <link>https://tproger.ru/news/openai-massovo-nanimaet--super-junior----dzhunov-bez-opyta-razrabotki--no-s-navykami-raboty-s-ii</link>
      <comments>https://tproger.ru/news/openai-massovo-nanimaet--super-junior----dzhunov-bez-opyta-razrabotki--no-s-navykami-raboty-s-ii?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/openai-massovo-nanimaet--super-junior----dzhunov-bez-opyta-razrabotki--no-s-navykami-raboty-s-ii</guid>
      <description><![CDATA[<p>OpenAI нанимает «super junior» — инженеров без опыта, но с навыками работы с ИИ. Они кодят через модели и ускоряют старших коллег</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/openai-massovo-nanimaet--super-junior----dzhunov-bez-opyta-razrabotki--no-s-navykami-raboty-s-ii">OpenAI массово нанимает «super junior» — джунов без опыта разработки, но с навыками работы с ИИ</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[OpenAI]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 03 Nov 2025 06:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>OpenAI меняет стратегию найма инженеров</b>: компания все чаще берет молодых специалистов без классического опыта в программировании, но с нативными навыками работы с искусственным интеллектом.</p><p>Об этом <a href="https://newsletter.pragmaticengineer.com/p/san-francisco-is-back">рассказал</a> глава прикладного и инженерного направлений ChatGPT <b>Сулман Чоудри </b>в беседе с <b>Гергели Оросом</b>, автором известной техрассылки <i>The Pragmatic Engineer</i>.</p><p>По словам Ороса, в OpenAI активно развивается новая модель — <b>связка «super senior + super junior»</b>. Опытный инженер отвечает за архитектуру и стратегические решения, а «супер-джун» берет на себя скорость и гибкость. Он использует ИИ-инструменты на уровне, недоступном старшим коллегам.</p><blockquote><i>«Один из таких джуниоров обиделся, когда его спросили, не помог ли ему Codex. Для него это слишком просто. Он использует сразу несколько экземпляров Codex, которые общаются между собой и выполняют разные части задачи»</i>, — рассказывает Орос.</blockquote><p>Эти специалисты — представители нового поколения <b>«AI-native» инженеров</b>, для которых взаимодействие с языковыми моделями — базовый навык, сродни владению Git или терминалом.</p><p>Они умеют быстро запускать несколько агентов, делить задачи между моделями и интегрировать результаты в код.</p><h2>Программы OpenAI для ранней карьеры</h2><p>Все это логично вписывается в собственные инициативы OpenAI — <b>Residency</b> и <b>Emerging Talent</b>. Там прямо говорится, что компания берет людей «на переходе» между non-tech и IT, если они способны быстро осваивать инженерные принципы с помощью ИИ.</p><p><i>«Мы ищем людей, которые думают, как инженеры, даже если у них нет традиционного опыта разработки»</i>, — говорится в описании программ.</p><h2>Контраст с рынком</h2><p>На общем фоне это решение выглядит почти парадоксально. 2025-й стал годом, когда большинство IT-компаний <b>сократили junior-позиции</b>: автоматизация и рост LLM-ассистентов сделали базовую разработку избыточной. Но OpenAI, наоборот, делает ставку на специалистов, выросших в новой парадигме — тех, кто <b>умеет кодить через ИИ, а не вместо него</b>.</p><p>Эксперты называют это возможным <b>сдвигом в отрасли</b>: если стратегия OpenAI сработает, за ней могут последовать другие компании, начав формировать команды, где ключевым навыком станет не знание конкретного языка, а <b>умение мыслить и строить системы в симбиозе с моделями</b>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Какие приложения установить на Windows и macOS</title>
      <link>https://tproger.ru/articles/kakie-prilozheniya-ustanovit-na-windows-i-macos</link>
      <comments>https://tproger.ru/articles/kakie-prilozheniya-ustanovit-na-windows-i-macos?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Валерия Турчак]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kakie-prilozheniya-ustanovit-na-windows-i-macos</guid>
      <description><![CDATA[<p>Список разбит по категориям: от браузеров и гейминга до утилит безопасности и инструментов для продуктивности.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kakie-prilozheniya-ustanovit-na-windows-i-macos">Какие приложения установить на Windows и macOS</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[Браузеры]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Slack]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[Windows 10]]></category>
      <category><![CDATA[Google Chrome]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Управление проектами]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[VPN]]></category>
      <category><![CDATA[Telegram]]></category>
      <category><![CDATA[Xbox]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[macOS]]></category>
      <category><![CDATA[Для продвинутых]]></category>
      <category><![CDATA[Intel]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Adobe]]></category>
      <category><![CDATA[Firefox]]></category>
      <category><![CDATA[IBM]]></category>
      <category><![CDATA[Mozilla]]></category>
      <category><![CDATA[Avast]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[NVIDIA]]></category>
      <category><![CDATA[Маркетинг]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[AMD]]></category>
      <category><![CDATA[YouTube]]></category>
      <category><![CDATA[Epic Games]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Бета]]></category>
      <category><![CDATA[Safari]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[PlayStation]]></category>
      <category><![CDATA[Microsoft Edge]]></category>
      <category><![CDATA[Discord]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[RPA]]></category>
      <category><![CDATA[Дизайн]]></category>
      <category><![CDATA[Figma]]></category>
      <category><![CDATA[Графы]]></category>
      <category><![CDATA[Markdown]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Notion]]></category>
      <category><![CDATA[Дизайн интерфейсов и UX]]></category>
      <category><![CDATA[Steam]]></category>
      <category><![CDATA[GPU]]></category>
      <category><![CDATA[Hardware]]></category>
      <category><![CDATA[iPhone]]></category>
      <category><![CDATA[MacBook]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 26 Oct 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Итак, вы только что настроили новый компьютер. Операционная система установлена, драйверы обновлены, и теперь пора заняться самым интересным — установкой программ. Но с чего начать? Какие приложения действительно необходимы, а какие просто занимают место?</p><p>Редакция Tproger сделала и адаптировала <a href="https://www.techspot.com/article/2974-desktop-software-essentials/">перевод подборки  программ для Windows и macOS</a>. Здесь вы найдёте проверенные временем решения для работы, развлечений и повседневных задач. Мы сосредоточились на бесплатных и условно-бесплатных приложениях с отличной репутацией, которые решают реальные задачи без навязывания ненужных функций.</p><p>Список разбит по категориям: от браузеров и гейминга до утилит безопасности и инструментов для продуктивности.</p><p>Неважно, опытный вы пользователь или новичок — здесь найдётся что-то полезное для каждого.</p><h2>Браузеры</h2><p>Браузер — это, пожалуй, самое важное приложение на вашем компьютере. Именно через него проходит большая часть вашей цифровой жизни: работа, развлечения, коммуникации. Выбор браузера влияет не только на скорость загрузки страниц, но и на конфиденциальность, безопасность и удобство работы.</p><ul><li><b>Большинство пользователей:</b> Chrome, Edge или Safari</li><li><b>Защита приватности: </b>Firefox, Brave, Ungoogled Chromium</li><li><b>Опытные пользователи:</b> Vivaldi</li><li><b>Максимальная анонимность: </b>Tor Browser</li></ul><h3>Google Chrome</h3><p>Chrome остаётся самым популярным браузером в мире — и не просто так. Он быстрый, стабильный и отлично интегрируется с экосистемой Google. Огромная библиотека расширений из Chrome Web Store позволяет настроить браузер под любые задачи. Синхронизация между устройствами работает безупречно: вкладки, пароли, закладки и история всегда под рукой.</p><p>Минус один, но существенный: Chrome прожорлив. Если у вас открыто больше десятка вкладок, он может съесть несколько гигабайт оперативной памяти. На компьютерах с 8 ГБ RAM и меньше это становится проблемой.</p><h3>Mozilla Firefox</h3><p>Firefox — это выбор тех, кто ценит приватность и открытость. Mozilla не зарабатывает на продаже ваших данных, а сам браузер активно развивается сообществом. Встроенные инструменты защиты от трекинга работают из коробки, блокируя рекламные сети и скрипты слежения.</p><p>По скорости Firefox не уступает Chrome, а по потреблению памяти даже выигрывает. Библиотека расширений чуть меньше, чем у Chrome, но все основные инструменты доступны.</p><h3>Microsoft Edge</h3><p>Edge построен на том же движке Chromium, что и Chrome, но при этом лучше оптимизирован для Windows. Microsoft вложилась в производительность: браузер работает быстро, потребляет меньше ресурсов и отлично интегрируется с системой.</p><p>Особенно приятны функции вроде Collections (коллекции вкладок для организации исследований), режим чтения и встроенный скриншотер. Edge поддерживает все расширения Chrome, так что переход безболезненный.</p><h3>Brave</h3><p>Brave — это Chrome на стероидах приватности. Браузер блокирует рекламу и трекеры по умолчанию, что делает сёрфинг быстрее и безопаснее. При этом он полностью совместим с расширениями Chrome.</p><p>Есть интересная фишка: Brave Rewards позволяет зарабатывать криптовалюту за просмотр приватной рекламы (если захотите её включить). Спорная механика, но как опция — почему нет. Для тех, кто хочет Chrome без Google и с упором на приватность, Brave — отличный выбор.</p><h3>Safari (только macOS)</h3><p>Если у вас Mac, Safari заслуживает внимания. Это самый энергоэффективный браузер для macOS: на MacBook он даёт ощутимо больше автономности по сравнению с Chrome или Firefox. Интеграция с экосистемой Apple безупречна: Handoff, синхронизация через iCloud, Reading List, автозаполнение паролей.</p><p>Safari быстрый, безопасный и не перегружен функциями. Единственный минус — библиотека расширений заметно скромнее, чем у конкурентов. Но для большинства задач базового функционала хватает.</p><h3>Ungoogled Chromium</h3><p>Для ультраосторожных Ungoogled Chromium удаляет всё отслеживание и сервисы Google — но вам придётся настраивать всё самостоятельно, так как в нём нет автообновлений или встроенной синхронизации.</p><p>Для максимально осторожных пользователей — это Chrome, из которого убрали всю телеметрию Google, отслеживание и облачные сервисы. Браузер работает, но требует ручной настройки: отсутствуют автоматические обновления и встроенная синхронизация между устройствами.</p><h3>Tor Browser</h3><p>Выводя приватность на следующий уровень, Tor Browser маршрутизирует ваш трафик через сеть Tor, анонимизируя ваш IP и многократно шифруя соединение. Он медленнее по задумке, но идеален, если ваш приоритет — максимальная анонимность, а не скорость или удобство.</p><h3>Vivaldi</h3><p>Vivaldi — браузер мечты для тех, кто хочет полного контроля. Стекирование вкладок, тайлинг, кастомные горячие клавиши, встроенная почта и календарь, веб-панели — это полноценный десктопный опыт внутри браузера. Хотите боковую панель браузера, открывающую ваши заметки, RSS-ленты или любой нужный сайт? Vivaldi это умеет.</p><h3>Arc</h3><p>Наконец, Arc — когда-то новичок на рынке браузеров, нацеленный на переосмысление UX: замена традиционной панели вкладок на боковую панель, акцент на веб-приложениях, интегрированные разделённые виды и easels для заметок и доски. К сожалению, компания за Arc прекратила разработку, чтобы полностью переключиться на ИИ с новым браузером, который сейчас в закрытой бета-версии.</p><h2>Управление паролями</h2><ul><li><b>Лучший бесплатный выбор:</b> Bitwarden</li><li><b>Также отлично:</b> 1Password, Dashlane, KeePass</li></ul><p>Миллионы людей продолжают использовать одни и те же слабые пароли на всех сайтах — или, что ещё хуже, держатся за классику вроде «123456». Даже сильные пароли мало помогают, если их повторяют или забывают. Конечно, большинство браузеров предлагают встроенные менеджеры паролей, но они ограничены, привязаны к одному браузеру и менее безопасны, чем специализированные решения.</p><p>Также не будем забывать о passkeys (ключах доступа). Если говорить практически, можно сказать, что passkeys объединяют концепцию пароля и двухфакторной аутентификации (2FA) в одно плавное действие, но гораздо безопаснее и гораздо менее раздражающе.</p><h3>Bitwarden</h3><p>Полностью опенсорсный, зашифрованный и щедрый даже в бесплатной версии. Вы получаете неограниченное количество паролей, синхронизацию между устройствами и приложения для всех платформ. Премиум ($10/год) добавляет безопасный обмен файлами и инструменты 2FA. Также есть доступные семейные и командные планы.</p><h3>1Password</h3><p>Премиум-решение с отполированным интерфейсом, сильной кроссплатформенной поддержкой и отличными функциями вроде Travel Mode (режим путешествий) и полной интеграцией passkeys.</p><h3>Dashlane</h3><p>Предлагает мониторинг даркнета, интеграцию VPN и плавный пользовательский опыт. Есть бесплатный тариф с ограниченными функциями, но премиум-версия конкурентоспособна.</p><h3>KeePassXC</h3><p>Отличная оффлайн-альтернатива, если хотите полного контроля и не против ручной синхронизации (или использования чего-то вроде Syncthing или Dropbox для синхронизации базы данных).</p><p>Пропустите LastPass — когда-то фаворит, он упал в немилость после повторных утечек безопасности. Для душевного спокойствия лучше поискать в другом месте.</p><h2>Продвинутые утилиты и дополнения к ОС</h2><ul><li><b>Поиск + лаунчеры:</b> Everything или Wox (Windows), Alfred или Raycast (macOS)</li><li><b>Пакетные менеджеры: </b>WinGet, Homebrew (macOS)</li><li><b>Для пользователей Windows:</b> PowerToys</li><li><b>Для пользователей Mac: </b>Rectangle</li><li><b>История буфера обмена: </b>ClipClip, Flycut (macOS)</li><li><b>Скриншоты + аннотации: </b>Monosnap</li></ul><h3>Winget</h3><p><b></b>Официальный менеджер пакетов Microsoft, встроенный в Windows 10 и 11. Работает похоже на Chocolatey, но разработан и поддерживается Microsoft. Homebrew — самый популярный менеджер пакетов для macOS. Позволяет быстро устанавливать, обновлять и управлять приложениями и CLI-инструментами с помощью команд в терминале.</p><h3>Everything</h3><p>Что касается поиска, Everything остаётся золотым стандартом сверхбыстрого поиска по именам файлов в Windows. Он индексирует диски за секунды и выдаёт почти мгновенные результаты с минимальной нагрузкой на систему. Если нужен функционал шире базового поиска, Wox использует движок Everything и добавляет мощные возможности лаунчера: поиск файлов, запуск приложений, калькулятор, перевод текста и расширения через плагины. Получается более гибкий опыт в духе Spotlight для Windows.</p><h3>Command Palette/Alfred/Raycast</h3><p>В который раз Microsoft не смогла существенно улучшить встроенный поиск Windows, хотя <b>Command Palette</b> в PowerToys даёт неплохой компромисс для тех, кто не хочет ставить сторонние утилиты.</p><p>На macOS <b>Alfred</b> по-прежнему главный лаунчер и утилита поиска. Он быстрый, интуитивный и в бесплатной версии включает историю буфера и настраиваемые поиски; расширенная автоматизация и «воркфлоу» доступны в Powerpack.</p><p>Тем, кто хочет современную облачно-интегрированную альтернативу с готовыми расширениями и встроенной поддержкой Notion, GitHub и Slack, стоит присмотреться к <b>Raycast</b> — это стильный, дружественный к разработчикам вариант, который стремительно набирает популярность.</p><h3>Менеджеры буфера обмена</h3><p>Они позволяют возвращаться к ранее скопированному — тексту, изображениям, ссылкам — и сильно ускоряют рутинные операции.</p><p>В Windows встроенная история буфера (Win + V) кое-как выручает, но продвинутым пользователям обычно хочется большего. В числе бесплатных рекомендаций — <b>ClipClip</b> для Windows и <b>Flycut</b> для macOS.</p><p>Когда речь о скриншотах и аннотациях, штатные инструменты macOS и Windows заметно выросли. Но многим всё равно удобнее сторонние решения. Нам по-прежнему нравится <b>Monosnap</b> за простоту и возможность мгновенно заливать снимки в облако для шаринга (и это бесплатно).</p><p><b>PowerToys</b> — набор полезных утилит от Microsoft для продвинутых пользователей Windows, повышающих продуктивность и упрощающих рабочие процессы. Среди инструментов: FancyZones для продвинутого раскладывания окон, PowerRename для пакетного переименования, Keyboard Manager для ремапинга клавиш, универсальный color picker и другие.</p><p><b>Rectangle</b> и <b>Magnet </b>— два самых популярных приложения на macOS для закрепления окон: быстрые выравнивание и ресайз по хоткеям или перетаскиванием, примерно как по умолчанию в Windows. Пользователям, пришедшим с Windows и скучающим по системному снапингу, одно из них жизненно необходимо.</p><p>Широко используемая альтернатива в Windows — <b>FancyZones</b> (часть PowerToys), предлагающая продвинутое управление окнами: настраиваемые сетки, зоны привязки и поддержку нескольких мониторов — поэтому это фаворит пауэр-пользователей на Windows.</p><h2>Для рутины и создания проектов</h2><ul><li><b>Бесплатные инструменты: </b>FreeOffice, LibreOffice и WPS Office</li><li>Microsoft Office за единовременную плату $49, Office 2024 — $129</li><li><b>Заметки: </b>Notion, OneNote, Obsidian</li><li><b>Бесплатный PDF-редактор: </b>PDFsam</li><li><b>Почтовые клиенты:</b> Thunderbird, eM Client</li></ul><p>Независимо от того, пишете ли вы тексты, планируете проект, кодите или наводите порядок в цифровой жизни, правильные инструменты решают многое. Сегодня выбор топовых приложений для продуктивности и разработки — часто бесплатных — лучше, чем когда-либо.</p><p><b>Microsoft Office</b> остаётся отраслевым стандартом для профессиональной продуктивности. Подписка Microsoft 365 открывает доступ к Word, Excel, PowerPoint, Outlook и включает 1 ТБ облачного хранилища.</p><p>Среди бесплатных альтернатив LibreOffice — мощный open-source комплект с сильным сообществом (хотя интерфейс некоторым кажется старомодным). Если нужна внешне более майкрософтовская альтернатива, попробуйте<b> FreeOffice </b>или <b>WPS Office Free</b> — у них хорошая совместимость.</p><p>На macOS <b>Pages</b>, <b>Numbers</b> и <b>Keynote</b> предустановлены и более чем достаточны для большинства задач, особенно если вы в экосистеме Apple.</p><h3>Знания и ведение заметок</h3><p><b>Notion</b> стал универсальной платформой организации: заметки, базы данных, to-do, управление проектами, создания совместных рабочих пространств. Если нужны более локальные заметки с синхронизацией между устройствами и поддержкой Markdown, <b>Obsidian</b> — любимец студентов и исследователей.</p><p>Для быстрых кроссплатформенных заметок <b>OneNote</b> — крепкий бесплатный вариант от Microsoft. В качестве альтернатив — <b>Simplenote</b> или open-source <b>Joplin</b>.</p><p>Если вы занимаетесь академической работой и научными статьями, <b>Zotero</b> — отличный open-source менеджер источников с интеграцией в браузер и совместными коллекциями. <b>Milanote</b> предлагает визуальный подход к заметкам и планированию — идеально для креативных пользователей.</p><h3>Работа с PDF</h3><p>Хотя Adobe Acrobat остаётся премиальным редактором PDF, бесплатные альтернативы вроде <b>PDFsam</b> позволяют без усилий объединять, разбивать, редактировать и поворачивать страницы.</p><h2>Инструменты для дизайна и создания контента</h2><p>Для дизайна два выделяющихся приложения хорошо дополняют набор продуктивности. <b>Figma Desktop</b> — совместная платформа интерфейс-дизайна, широко используемая UI/UX-дизайнерами и фронтенд-разработчиками. Десктоп-версия работает быстрее, чем браузер, и лучше интегрируется с ОС — это удобно для сложных дизайн-систем и коллаборации в реальном времени.</p><p><b>Canva</b> с интуитивным drag-and-drop превосходно чувствует себя и как десктоп-приложение. Отлично подходит для быстрых графических материалов для соцсетей, маркетинга, постеров и презентаций. Благодаря тысячам шаблонов и совместной работе это фаворит как у профи, так и у новичков.</p><h2>Почтовые клиенты</h2><p>Если вы предпочитаете отдельный почтовый клиент, у <b>eM Client</b> много функций, бесплатный — до двух аккаунтов. <b>Mozilla</b> <b>Thunderbird</b> — мощная open-source альтернатива с удобной настраиваемостью, а <b>Mailbird</b> — вариант с упором на продуктивность для тех, кого не пугает подписка.</p><h2>Инструменты разработчика</h2><ul><li><b>Редакторы кода и текста:</b> VS Code, Cursor, Sublime Text</li><li><b>Система контроля версий:</b> SourceTree, GitHub Desktop</li><li><b>Контейнеры: </b>Docker</li><li><b>Локальные LLM: </b>Ollama</li><li><b>SFTP, загрузка файлов:</b> WinSCP, Forklift</li></ul><p>Для разработчиков <b>Visual Studio Code</b> — безусловный вариант. Бесплатный, лёгкий, но мощный, кроссплатформенный — тысячи расширений покрывают практически любой язык, фреймворк или инструмент. Набирающая популярность альтернатива — <b>Cursor</b>, редактор на базе VS Code с усиленной AI-помощью. Он подходит для связки с LLM: даёт inline-подсказки, генерирует код, рефакторит и позволяет редактировать кодовую базу.</p><p>При этом<b> Sublime Text </b>остаётся для скорости и простоты, а <b>Notepad++</b> — отличный лёгкий редактор для быстрых правок в Windows.</p><p>Для Git графические клиенты <b>SourceTree</b> и <b>SmartGit</b> дают понятный интерфейс для управления репозиториями на GitHub, GitLab и не только. <b>GitHub Desktop</b> раньше был простоват и не слишком хорош, но сейчас существенно прибавил — всё ещё простой для работы, но в хорошем смысле.</p><p>Для локальных окружений, API-тестирования или терминального воркфлоу инструментов — пруд пруди. Например, <b>Docker Desktop</b> стал стандартом для тех, кто собирает и запускает контейнеризированные приложения на разных платформах. Он упрощает настройку окружений и держит систему чистой.</p><p><b>Ollama</b> позволяет запускать большие языковые модели (LLM) локально с минимальной настройкой. Поддерживает модели вроде LLaMA, Mistral и другие open-weight альтернативы GPT, так что можно работать с ИИ прямо на своём компьютере без отправки данных в облако.</p><p>Если вы работаете с облачными хранилищами или SFTP, WinSCP (Windows) и ForkLift (macOS) — отличные клиенты с двухпанельным управлением файлами, синхронизацией и автоматизацией. На Mac также популярны <b>Commander One</b> и <b>Transmit</b> — у них есть встроенные подключения к удалённым и облачным путям.</p><h3>Безопасность</h3><p>И Windows, и macOS сегодня предлагают более чем достойную встроенную защиту. С защитой в реальном времени, интеграцией с файерволом и биометрией вроде <b>Windows Hello</b> и <b>Touch ID</b>. Для обычных пользователей, которые соблюдают гигиену безопасности: не скачивают сомнительное ПО, используют менеджеры паролей и включают 2FA — встроенной защиты часто хватает.</p><p>Для продвинутых пользователей есть дополнительные варианты.</p><p>Отличное первое дополнение — <b>Malwarebytes</b>. Это давний фаворит в обнаружении и удалении malware, adware и руткитов; бесплатная версия по-прежнему хороша для ручных сканов. В платной — защита в реальном времени без ощутимой просадки производительности.</p><p>Если не хочется ставить традиционный антивирус, есть достойные альтернативы. <b>Emsisoft Emergency Kit</b> — мощный портативный сканер, который можно запускать с флешки: идеально для редких глубоких сканов или лечения заражённых систем без установки чего-либо. Просто подключаете, когда нужно.</p><p>Ещё один отличный инструмент — <b>VirusTotal</b>: бесплатный веб-сервис, который проверяет файлы и URL через десятки антивирусных движков. Прежде чем открывать подозрительную загрузку, можно залить файл на VirusTotal.com или использовать их расширение для браузера, чтобы проверять ссылки в реальном времени. Быстро, просто и удобно для осторожных пользователей.</p><p>Мы не поклонники установки антивирусов на каждый компьютер и не полностью в курсе, какие сейчас показывают лучшие результаты. Тем не менее, <b>AV-Tes</b>t давно и регулярно оценивает популярные решения, поэтому советуем смотреть их свежие отчёты. В текущем списке высокооценённых — <b>Avast, BitDefender, ESET </b>и другие; многие из них предлагают бесплатные версии для пробы.</p><h3>Удалённый доступ и вспомогательные утилиты</h3><p><b>RustDesk</b> стал современным, ориентированным на приватность аналогом <b>TeamViewer</b>. Он с открытым исходным кодом, быстрый и работает кроссплатформенно.</p><p>Тем, кому нужны более устоявшиеся коммерческие решения, подойдёт <b>AnyDesk</b>, который остаётся лёгким и надёжным вариантом для личного и командного использования.</p><p>Превращение смартфона в пульт дистанционного управления компьютером бывает невероятно удобно — будь то презентации, потоковое видео или просто навигация с дивана.</p><p><b>Remote Mouse</b> — простой и эффективный способ эмулировать мышь и клавиатуру с телефона. Для более продвинутых сценариев можно использовать приложения вроде <b>Unified Remote.</b></p><h2>Редактирование изображений и видео</h2><ul><li><b>Профессиональный видеомонтаж:</b> DaVinci Resolve</li><li><b>Простой видеомонтаж: </b>CapCut</li><li><b>Редакторы изображений:</b> GIMP, PhotoDemon, Pixelmator Pro</li><li><b>Бесплатное улучшение изображений:</b> Upscayl</li><li><b>RAW-редактирование:</b> RawTherapee</li><li><b>Видеоконвертация:</b> HandBrake</li></ul><p>Если вам нужен бесплатный инструмент для редактирования изображений, <b>GIMP</b> — один из самых мощных вариантов. Он предоставляет профессиональные возможности, такие как слои, маски и настраиваемые плагины, что делает его идеальным для продвинутых пользователей. Если вы ищете более лёгкий редактор с чистым интерфейсом, стоит обратить внимание на <b>PhotoDemon</b>. Он работает как портативное приложение на Windows, поддерживает слои и редактирование — отличный выбор для быстрых правок или ретуши.</p><p>Если вы хотите увеличивать разрешение изображений без потери качества, <b>Upscayl</b> — мощный и бесплатный инструмент для апскейла. Он кроссплатформенный, и по нашим тестам показывает результаты на уровне платных решений вроде Topaz.</p><p>Для векторной графики — логотипы, иллюстрации — <b>Inkscape</b> является достойным open-source вариантом с полной поддержкой редактирования SVG. <b>Krita</b> — ещё один отличный бесплатный инструмент, особенно подходящий для цифровой живописи и художественного творчества.</p><p>Для редактирования RAW-фотографий, <b>Darktable</b> и <b>RawTherapee</b> — два высококлассных open-source аналога Adobe Lightroom. Их широко используют фотографы, которым нужна работа с изображениями без подписки.</p><p>Для простых GIF-анимаций <b>ScreenToGif</b> — удобная утилита, мгновенно записывающая область экрана и экспортирующая в GIF или другие форматы с оверлеями.</p><p>Среди платных фоторедакторов <b>Adobe Photoshop</b> остаётся лидером, но для macOS есть <b>Pixelmator Pro</b> — мощное приложение с разовой оплатой, а <b>Affinity Photo</b> предлагает профессиональные возможности по более доступной цене.</p><h3>Видеомонтаж и конвертация</h3><p><b>DaVinci Resolve</b> считается лучшим бесплатным профессиональным ПО. Его используют и энтузиасты, и профессионалы — от простого тримминга до цветокоррекции и сложного постпродакшена.</p><p><b>Shotcut</b> и <b>Kdenlive</b> — тоже сильные бесплатные варианты, предлагают более простой фукнционал с хорошим набором функций для новичков и продвинутых пользователей. <b>CapCut</b>, изначально мобильное приложение, теперь доступен на десктопе — идеально подходит для быстрых монтажей и роликов для соцсетей.</p><p>Для пользователей macOS <b>iMovie </b>предустановлен и остаётся надёжным вариантом для базовых видео. Если вам нужно просто конвертировать или сжимать видео в современные форматы, <b>HandBrake</b> — проверенное бесплатное решение с поддержкой и вариацией входных и выходных форматов.</p><p>Тем, кто ищет топовый профессиональный монтаж, подойдут <b>Adobe Premiere Pro</b> и<b> Final Cut Pro</b>, но там есть дорогая подписка и более высокий порог входа.</p><h2>Коммуникации и совместная работа</h2><ul><li><b>Для повседневной связи: </b>WhatsApp, Messenger и Zoom, если у вас нет FaceTime</li><li><b>Для приватности: </b>Signal</li><li><b>Для работы:</b> Slack, Teams</li><li><b>Для игр и общения: </b>Discord</li></ul><p>Выбор коммуникационных и мессенджерных приложений в первую очередь зависит от того, с кем вы общаетесь — с семьёй, друзьями, коллегами или игровым сообществом. Вот актуальная картина:</p><p>Для личной переписки <b>WhatsApp</b> и <b>Facebook Messenger</b> остаются самыми массовыми платформами по всему миру. У них есть десктопные клиенты и встроенное сквозное шифрование по умолчанию. <b>Telegram</b> также крайне популярен благодаря синхронизации между устройствами и поддержке крупных чатов. Пользователи Apple продолжают активно использовать <b>iMessage</b> для приватного, шифрованного общения в экосистеме Apple.</p><p>Из видеоконференций <b>Zoom</b> остаётся одним из лидеров для групповых звонков и онлайн-ивентов, предлагая локальные записи, демонстрацию экрана и комнаты (breakout rooms). Однако бесплатный тариф ограничивает 1:1 звонки 40 минутами, если не перейти на платный план. Zoom поддерживает сквозное шифрование, но при включении E2EE отключаются некоторые функции вроде облачной записи и комнат.</p><p><b>Google Meet</b> — отличный браузерный аналог без необходимости установки, который заметно улучшился по качеству и удобству использования. Многие компании применяют Meet в ежедневной работе и гибридных форматах. Если ваша организация использует Microsoft 365, скорее всего, вы работаете в <b>Microsoft Teams</b>, который уже заменил Skype на корпоративном уровне. Teams поддерживает большие созвоны, обмен файлами и глубоко интегрирован с Office. Сквозное шифрование доступно, но только для 1:1 звонков.</p><p><b>FaceTime</b> по-прежнему отличный для пользователей Apple, и благодаря новым обновлениям к звонку теперь могут присоединяться и пользователи Android/Windows по ссылке через браузер.</p><p>Когда приватность критична, <b>Signal</b> — один из лучших вариантов. Разработан некоммерческой организацией, бесплатен, open-source, без рекламы, использует надёжное сквозное шифрование для сообщений и звонков.</p><p>Для рабочих коммуникаций<b> Slack</b> и <b>Teams</b> продолжают использоваться в бизнес-среде. Бесплатный тариф Slack ограничивает историю 90 днями и звонки, но остаётся любимцем стартапов и малых команд благодаря интеграциям и ботам. <b>Cisco Webex</b> — также крепкий вариант, особенно популярен в корпоративной среде.</p><p>Если вы работаете с креативными командами, сообществами или геймерами, <b>Discord</b> стал явным лидером. Изначально созданный для игр, он превратился в полноценную коллаборативную платформу с текстом, голосом и видео, стримингом экрана и ботами для автоматизации. Многие комьюнити — и даже IT-компании — используют Discord как основной рабочий инструмент.</p><p>Для внутриигрового голосового чата <b>TeamSpeak </b>остаётся олдскульным достойным вариантом: можно использовать анонимно и получать полный контроль над сервером. Встроенный чат Steam лучше, чем раньше, и помогает в игровой координации, но большинство всё же выбирает Discord.</p><h2>Гейминг, моддинг и стриминг</h2><ul><li><b>Игровые платформы: </b>Steam, Epic Games, EA App, Ubisoft, GOG</li><li><b>Последние драйверы для GPU:</b> Nvidia GeForce, AMD Radeon, Intel Arc</li><li><b>Стриминг:</b> OBS Studio</li></ul><p><b>Steam</b> остаётся центром PC-игр. Это не только магазин, но и социальная платформа, лаунчер и площадка с модами, облачными сохранениями и встроенным стримингом. Регулярные распродажи, поддержка контроллеров и сообщества делают его обязательным для любого PC-геймера.</p><p>Не менее важно установить Epic <b>Games Store</b>. Хотя библиотека меньше, он регулярно раздаёт бесплатные игры, доступные любому с аккаунтом Epic. Это также must-have, если вы играете в Fortnite.</p><p>Помните: не все издатели размещают игры на Steam или Epic. Для тайтлов EA понадобится <b>EA App (ранее Origin)</b>, для Ubisoft — <b>Ubisoft Connect</b>, для Blizzard/Activision — <b>Battle.net</b>, а GOG Galaxy не только предлагает DRM-free классику, но и может агрегировать игры из других лаунчеров.</p><p>Некоторые сверхпопулярные игры распространяются отдельно: Minecraft (через Minecraft.net или Microsoft Store), Roblox, League of Legends и Valorant (через лаунчер Riot Games). Если вы новичок и ищете что-то лёгкое, можно начать с free-to-play тайтлов или классики вроде <b>Brutal Chess</b> или <b>GZDoom</b>.</p><p>Если вы играете с геймпадом, Windows поддерживает Xbox-контроллеры из коробки. PlayStation-контроллеры теперь тоже отлично работают: Steam через <b>Steam Input </b>поддерживает DualShock 4 и DualSense практически во всех играх. При необходимости глубокой кастомизации можно использовать DS4Windows, но большинству хватает возможностей Steam.</p><p>Если вас интересует моддинг, хороший менеджер модов время в этой жизни:</p><ul><li><b>Mod Organizer 2</b> — лучший для RPG Bethesda (Skyrim, Fallout).</li><li><b>Vortex (от Nexus Mods)</b> — дружелюбный к новичкам и поддерживает широкий перечень игр.</li></ul><p>Для записи геймплея или стриминга <b>Nvidia ShadowPlay</b> и <b>AMD Radeon ReLive</b> подходят для простых задач. Но для стриминга с вебкой, сценами, оверлеями или многосценовым продакшеном <b>OBS Studio</b> — безальтернативный лидер. Он бесплатный, open-source и подходит как новичкам, так и про-стримерам (Twitch, YouTube, Kick и т.д.). <b>SignalRGB</b> помогает синхронизировать весь RGB-зоопарк и задавать динамические эффекты.</p><h2>Мониторинг железа и разгон</h2><ul><li><b>Мониторинг: </b>CPU-Z, HWMonitor, HWiNFO64</li><li><b>Настройка и разгон:</b> Afterburner, FanControl, ThrottleStop, SignalRGB</li></ul><p>Одно из первых дел, которое стоит сделать после сборки ПК — убедиться, что компоненты соответствуют ожиданиям и работают корректно. К счастью, существует много инструментов, позволяющих мониторить, тестировать и настраивать железо.</p><p>Начать стоит с <b>CPU-Z</b> — классического бесплатного инструмента, показывающего информацию о CPU, материнской плате, оперативной памяти и других компонентах. Он также умеет запускать простой стресс-тест и бенчмарк для проверки стабильности.</p><p>Для более широкого мониторинга <b>HWMonitor</b> показывает температуры, напряжения и скорости вентиляторов в реальном времени. Если нужно ещё глубже и с более гибким интерфейсом — <b>HWiNFO64</b> считается одним из лучших: поддерживает логирование датчиков и интеграцию с оверлеями (например, RTSS или Rainmeter).</p><p>Чтобы проверить хранилище, <b>CrystalDiskMark</b> измеряет скорость чтения/записи SSD и HDD — это помогает понять, соответствует ли диск заявленным характеристикам. Глубже оценить здоровье накопителя можно в <b>Hard Disk Sentinel</b>, который анализирует SMART-данные, оценивает срок службы и предлагает ограниченный ремонт.</p><p>С точки зрения охлаждения, всё больше геймеров используют утилиты для настройки вентиляторов. <b>FanControl</b> — актуальный бесплатный фаворит: поддерживает сложные кривые оборотов, привязку к датчикам, и совместим с большинством современных материнских плат. На Mac одной из лучших утилит остаётся<b> Macs Fan Control.</b></p><p>Для настройки видеокарт долгое время стандартом был <b>MSI Afterburner</b> — для разгона, настройки вентиляторов и мониторинга с RTSS-оверлеем. Однако из-за замедления обновлений многие сегодня используют встроенные утилиты от <b>Nvidia (GeForce Experience/Control Panel)</b> и <b>AMD (Adrenalin Software)</b>.</p><p>Если вы меняете видеокарту или подозреваете проблемы с драйверами, обязательно используйте <b>Display Driver Uninstaller</b> (DDU) — он полностью очищает систему от старых драйверов перед переустановкой.</p><p>Если вы играете на ноутбуке или хотите снизить нагрев и повысить автономность, <b>ThrottleStop</b> остаётся одним из лучших инструментов для андервольта CPU и настройки энергопрофилей.</p><p>Тем, кто серьёзно подошёл к разгону CPU и GPU, пригодятся фирменные инструменты вроде <b>Intel XTU (для Intel) и AMD Ryzen Master</b> — они дают контроль над частотами, напряжениями и лимитами мощности.</p><h2>Управление файлами</h2><ul><li><b>Поиск больших файлов:</b> SpaceSniffer, WizTree, Disk Drill (macOS)</li><li><b>Поиск дубликатов: </b>dupeGuru</li><li><b>Архивы и ZIP: </b>PeaZip, The Unarchiver</li><li><b>Очистка: </b>BCUninstaller, CCleaner Portable, AppCleaner (macOS)</li></ul><p>Чтобы грамотно управлять файлами и освобождать место, нужно понимать, что именно занимает пространство. На Windows популярны <b>WinDirStat и WizTree </b>— быстрые бесплатные инструменты для визуализации диска. <b>SpaceSniffer</b> предоставляет динамическую схему.</p><p>На macOS — <b>GrandPerspective и Disk Drill </b>предлагают аналогичный функционал, а <b>DaisyDisk</b> — один из самых красивых платных вариантов с молниеносным сканированием.</p><p>Если дубликаты засоряют диск, <b>dupeGuru</b> (open-source) отлично справляется с поиском повторяющихся изображений и музыки, даже слегка изменённых.</p><p>Для пакетного переименования файлов (например, фоточек с камеры) существует гибкий <b>Bulk Rename Utility</b>. Если нужно что-то попроще: <b>PowerRename</b> из PowerToys (Windows) или встроенный инструмент в <b>Finder</b> (macOS) подходят большинству.</p><p>Встроенный <b>File Explorer</b> в Windows недавно получил вкладки и стал удобнее, но <b>Files</b> (open-source) — современная альтернатива с улучшенным UX. Кто-то ещё пользуется <b>Total Commander</b> или <b>Directory Opus</b>, благодаря расширяемости и скриптам, хотя новичкам они кажутся устаревшими. Для просмотра изображений по-прежнему незаменим <b>IrfanView</b>.</p><p>Для работы с архивами, если не устраивает встроенный ZIP-менеджер Windows, скачайте <b>7-Zip</b> или <b>PeaZip</b>. На Mac лучшим бесплатным инструментом остаётся <b>The Unarchiver</b>.</p><p>Для очистки системы важно выбирать надёжные утилиты. На Windows, <b>BCUninstaller (Bulk Crap Uninstaller)</b> — один из самых проверенных для удаления программ и их хвостов. <b>BleachBit</b> и <b>Wise Disk Cleaner</b> — безопасные альтернативы <b>CCleaner</b> (лучше использовать Portable-версию, так как стационарная испортила репутацию). На Mac <b>AppCleaner</b> всё ещё любим за полное удаление приложений без мусора.</p><p>Если вы организуете большую библиотеку медиа, стоит взглянуть на open-source <b>TagSpaces</b>, позволяющий тегировать файлы локально, без облака.</p><h2>Облачное хранилище и резервное копирование</h2><ul><li><b>Простая синхронизация: </b>Dropbox, Google Drive</li><li><b>Фото между устройствами:</b> Apple iCloud, Google Photos</li><li><b>Приватность: </b>pCloud, Proton Drive, Internxt</li><li><b>Полные бэкапы:</b> Backblaze, IDrive</li></ul><h3>Базовое облачное хранилище</h3><p><b>Dropbox</b> — один из самых простых в использовании, хотя бесплатных 2 ГБ мало.</p><p><b>
Google Drive</b> — 15 ГБ бесплатно, используется Gmail, Docs и Photos. Идеален для Android.</p><p><b>
OneDrive</b> — идёт в комплекте с Windows и Microsoft 365. 1 ТБ включён в большинство Office-планов. Хотя по скорости и интерфейсу уступает Dropbox/Google.</p><p><b>
iCloud Drive</b> — лучший выбор для пользователей Apple, глубокая интеграция с macOS/iOS. Бесплатно 5 ГБ, далее по планам до 2 ТБ.</p><p><b>
Proton Drive</b> — шифрованная альтернатива от создателей ProtonMail.</p><h3>Фото и видео</h3><p>На macOS приложение <b>Photos</b> автоматически создаёт альбомы по людям и локациям, синхронизирует всё через iCloud.</p><p>На Windows мы часто рекомендуем <b>Google Photos</b>, который предлагает аналогичный набор функций и автоматизацию. Для пользователей Android — это стандарт по умолчанию. Да, раньше было безлимитно, теперь фото занимают общее место Google Drive (15 ГБ), которое быстро заканчивается.</p><h3>Полные бэкапы</h3><p>Если требуется сохранять всю систему, терабайты медиа, состояние дисков используйте отдельные сервисы резервного копирования.</p><p><b>Backblaze</b> — топ в этой категории: фиксированная цена (~$8/месяц за устройство), безлимитное хранилище, минимум настроек: установил и забыл.</p><p><b>IDrive</b> — более контролируемый вариант, поддерживает несколько устройств, внешние диски и версионность файлов.</p><p>Простой для не-технарей — <b>Carbonite</b>, с возможностью быстрого восстановления и круглосуточной поддержкой.</p><p>Профессионалам — <b>Acronis Cyber Protect</b>: клон дисков, анти-вымогатель, гибридное облако.</p><h3>Для особо чувствительных данных</h3><p>Если вы храните личные финансовые документы или медицинские сведения, стоит выбрать end-to-end решений.</p><p><b>pCloud</b> предлагает клиентское шифрование (через платный «Crypto»). Даже при взломе аккаунта файлы не расшифруются без ключа.</p><p><b>Proton Drive </b>— аналогичный подход, с прозрачностью open-source.</p><h2>Прочие полезные инструменты, не вошедшие в другие разделы</h2><p><b>Google Earth</b> — для любителей карт и планировки.</p><p><b>qBittorrent</b> — лучший torrent-клиент: чистый, без рекламы, с поиском. Альтернатива — легковесный Transmission или кастомизируемый Deluge.</p><p><b> iMazing</b> — must-have для владельцев iPhone: резервные копии, экспорт медиа, проверка батареи, конвертация HEIC.</p><p><b>AirDroid</b> — аналог для Android: управление файлам, уведомления, SMS с ПК.</p><p><b>Rufus</b> — лидер по созданию загрузочных USB-дисков для Windows/Linux.</p><p><b>Open Shell </b>— возвращает классическое меню «Пуск» в стиле Windows 7.</p><p><b>Stretchly</b> — напоминает делать перерывы — полезно удалёнщикам и фрилансерам.</p><p><b>AutoHotkey</b> — скриптовый движок для Windows: переназначение клавиш, макросы, автоматизация.</p><p><b>VPN: </b>бесплатные — ProtonVPN, Windscribe, TunnelBear (с лимитом). Платные — ProtonVPN, NordVPN.</p><p><b>Calibre</b> — лучшее бесплатное решение для чтения, организации и конвертации e-book (EPUB, MOBI, PDF и др.).</p><h2>Заключение</h2><p>Итак, мы прошлись по основным категориям приложений, которые стоит установить на новый компьютер. Конечно, этот список не исчерпывающий — у каждого свои задачи и предпочтения. Но если вы установите хотя бы половину из перечисленного, ваш компьютер станет гораздо удобнее и функциональнее.</p><p>Несколько советов напоследок:</p><ol><li><b>Не захламляйте систему.</b> Устанавливайте только то, что действительно используете. Чем меньше фоновых процессов — тем быстрее работает компьютер.</li><li><b>Следите за обновлениями.</b> Большинство программ обновляются автоматически, но некоторые требуют ручного апдейта. Свежие версии — это не только новые функции, но и закрытые уязвимости.</li><li><b>Делайте резервные копии.</b> Никакие утилиты не спасут от отказа жёсткого диска. Регулярный бэкап на внешний носитель или в облако — обязательная практика.</li><li><b>Экспериментируйте. </b>Попробуйте несколько браузеров, редакторов, плееров. То, что подходит большинству, может не подойти именно вам.</li><li><b>Читайте отзывы.</b> Перед установкой незнакомого приложения загляните на форумы или Reddit. Сообщество быстро выявляет проблемы и подводные камни.</li></ol><p>Теперь ваш компьютер готов к работе, учёбе, развлечениям — и чему угодно ещё. Главное — не забывайте, что инструменты важны, но ещё важнее то, как вы их используете. Удачи!</p>]]></content:encoded>
    </item>
  </channel>
</rss>