05 марта 2026 № 1 (2026)

ROSARIUM

газета советского программиста

Теория: патчи, форматы и применение

На этой странице

Когда нужны патчи

Типичные ситуации

  1. Ошибка компиляции на новом компилятор. Upstream писал код под GCC 12, а в ROSA стоит GCC 14, который стал строже. Код не компилируется из-за нового предупреждения с -Werror.

  2. Дистрибутив-специфичные пути. Программа ищет конфиг в /etc/htop/htoprc, а в ROSA принято хранить в /etc/htoprc. Нужно поменять путь.

  3. Безопасность (CVE). Найдена уязвимость, upstream выпустил фикс, но новая версия ещё не вышла. Нужно взять конкретный коммит.

  4. Бэкпорт исправления бага. В upstream уже починили баг, но мы не можем обновиться на новую версию (слишком много изменений). Забираем только нужный коммит.

  5. Интеграция с дистрибутивом. Добавление desktop-файла, иконок, AppStream-метаданных, systemd-юнитов.

Принцип: минимальный патч

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

diff -u vs git format-patch

Способ 1: diff -u (классический)

diff -u файл_оригинал файл_изменённый > my.patch

Или для целого каталога:

diff -ruN каталог_оригинал/ каталог_изменённый/ > my.patch

Флаги:

  • -r — рекурсивно (все файлы в подкаталогах)
  • -u — unified формат (с контекстом ---/+++)
  • -N — включать новые файлы (которых нет в оригинале)

Когда использовать: если у вас нет git (редко) или нужен простой одиночный diff между двумя файлами.

Способ 2: git format-patch (рекомендуемый)

git format-patch -1          # создать патч из последнего коммита
git format-patch -1 --stdout > my.patch   # вывести в файл
git format-patch -3          # три последних коммита → три файла

Преимущества:

  • Включает метаданные: автор, дата, описание коммита
  • Номерация (0001-, 0002-) — порядок применения очевиден
  • Формат совместим с git am — можно применить обратно в git
  • Проще всего создавать из upstream-коммитов

Когда использовать: почти всегда. Это стандарт в мире RPM-пакетирования.

Уровни патча (-p0, -p1, -p2)

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

Допустим, в патче написано:

--- a/src/htop.c
+++ b/src/htop.c
УровеньЧто отрезаетсяРезультатКогда использовать
-p0НичегоИщет файл a/src/htop.cdiff -ruN old/ new/
-p1Первый компонент (a/)Ищет файл src/htop.cgit format-patch (стандарт)
-p2Два компонента (a/src/)Ищет файл htop.cРедко

Правило: git format-patch всегда создаёт пути с a/ и b/ префиксами, поэтому для git-патчей всегда нужен -p1.

%autosetup vs %setup + %patch

Современный способ: %autosetup (рекомендуется)

Patch0:  htop-disable-werror.patch
Patch1:  htop-fix-build.patch

%prep
%autosetup -p1

%autosetup -p1 делает всё за вас:

  1. Распаковывает архив (как %setup)
  2. Применяет все патчи (Patch0, Patch1, …) с уровнем -p1
  3. В правильном порядке (по номерам)

Устаревший способ: %setup + %patch

Patch0:  htop-disable-werror.patch
Patch1:  htop-fix-build.patch

%prep
%setup -q
%patch0 -p1
%patch1 -p1

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

Рекомендация: используйте %autosetup -p1, если все патчи с одинаковым уровнем. Это проще и современнее.

Где применяются патчи

Патчи применяются к распакованным исходникам в каталоге:

~/rpmbuild/BUILD/htop-3.3.0/

Это каталог, куда %autosetup распаковал архив. Все пути в патче отсчитываются от этого каталога (после отрезания -p уровня).