Product SiteDocumentation Site

11.3. Патчи при сборке пакетов

При разработке с помощью Gear существует правило не изменять исходники в части git-репозитория, соответствующей авторским исходным текстам. Изменения разработчиков, сопровождающих пакет, надо держать отдельно; один из вариантов — в виде патчей. Этот вариант хорош тем, что явно поддерживается в структуре файла спецификации.
Соберём примитивный пакет, который затем преобразуем с помощью патча:
@user: hello-upgrade-pkg/prog.c
#include <stdio.h>

char str[] = "Hello, Packager!";

int main(void) {
       printf("%s\n", str);
       return 0;
}
@user: hello-upgrade-pkg/Makefile
TRASH = *.o *~ .gear/*~
GENS = hello-upgrade
CC = cc
CFLAGS = -O0 -g -Wall

hello-upgrade:  prog.o
       $(CC) $(CFLAGS) $< -o $@

clean:
       rm -f $(TRASH)

distclean:      clean
       rm -f $(GENS)
@user: hello-upgrade-pkg/.gear/rules
spec:   .gear/hello-upgrade.spec
tar.gz: . name=@name@-@version@
@user: hello-upgrade-pkg/.gear/hello-upgrade.spec
Name: hello-upgrade
Version: 1.0
Release: alt1

Summary: Test pkg with patch

License: GPL-3.0-or-later
Group: Development/Other

Source0: %name-%version.tar.gz

%description
This is a small testing package, builded with patch

%prep
%setup

%build
%make_build

%install
install -D %name %buildroot%_bindir/%name

%files
%_bindir/%name


%changelog
* Sat Aug 02 2025 UsamG1t <usamg1t@altlinux.org> 1.0-alt1
- Initial Build
Программа пакета просто печатает сообщение на экран:
@user
[user@VM hello-upgrade-pkg]$ gear-hsh --lazy
<...>
[user@VM hello-upgrade-pkg]$ cp ~/hasher/repo/x86_64/RPMS.hasher/hello-upgrade-1.0-alt1.x86_64.rpm ~/hasher/chroot/.in/
[user@VM hello-upgrade-pkg]$ hsh-shell --rooter
@rooter
[root@localhost .in]# rpm -i hello-upgrade-1.0-alt1.x86_64.rpm
<13>Aug  2 15:58:59 rpm: hello-upgrade-1.0-alt1 1754150276 installed

[root@localhost .in]# hello-upgrade
Hello, Packager!
[root@localhost .in]#
Теперь добавим патч с изменениями. Для его создания воспользуемся git diff — встроенной в GIT утилитой определения изменений между коммитами. Её формат совместим с unified diff («лишние» строки с полями, относящимися к коммиту, утилита patch пропустит). Для начала добавим все изменения. Добавим новую функцию, которая будет возвращать сообщение для вывода. Отредактируем исходный код программы и Makefile для сборки:
@user: hello-upgrade-pkg/fun.c
#include <stdio.h>
#include <stdlib.h>

void return_str(char* str) {
       snprintf(str, 30, "Hello, Upgraded Packager!");
}
@user: hello-upgrade-pkg/fun.h
void return_str(char* str);
@user: hello-upgrade-pkg/prog.c
#include <stdio.h>
#include <stdlib.h>
#include "fun.h"

int main(void) {
       char* result = malloc(30 * sizeof(char));
       return_str(result);
       printf("%s\n", result);
       free(result);
       return 0;
}
@user: hello-upgrade-pkg/Makefile
TRASH = *.o *~ .gear/*~
GENS = hello-upgrade
CC = cc
CFLAGS = -O0 -g -Wall

hello-upgrade:  prog.o fun.o
       $(CC) $(CFLAGS) $^ -o $@
clean:
       rm -f $(TRASH)

distclean:      clean
       rm -f $(GENS)
Теперь сделаем единый коммит и сохраним в виде патча все изменения (можно было сделать несколько коммитов, тогда при описании изменений рассматривались бы не соседние, а разнесённые в ветке коммиты, однако результат был бы таким же):
@user
[user@VM hello-upgrade-pkg]$ ls
fun.c  fun.h  Makefile  prog.c
[user@VM hello-upgrade-pkg]$ git status
On branch master
Changes not staged for commit:
 (use "git add <file>..." to update what will be committed)
 (use "git restore <file>..." to discard changes in working directory)
       modified:   Makefile
       modified:   prog.c

Untracked files:
 (use "git add <file>..." to include in what will be committed)
       fun.c
       fun.h

no changes added to commit (use "git add" and/or "git commit -a")

[user@VM hello-upgrade-pkg]$ git add fun.*
[user@VM hello-upgrade-pkg]$ git commit -a -m "Patch commit"
[master 9013147] Patch commit
4 files changed, 14 insertions(+), 4 deletions(-)
create mode 100644 fun.c
create mode 100644 fun.h

[user@VM hello-upgrade-pkg]$ git log --oneline
9013147 (HEAD -> master) Patch commit
fa6269f 1.0-alt1
e30b38f 1.0-alt1
9be6d7f 1.0-alt1
[user@VM hello-upgrade-pkg]$ git diff fa6269f 9013147 --patch --output=hello-upgrade-1.0-alt1.patch

[user@VM hello-upgrade-pkg]$ cat hello-upgrade-1.0-alt1.patch
index 3f543ad..c39cafe 100644
--- a/Makefile
+++ b/Makefile
@@ -3,8 +3,8 @@ GENS = hello-upgrade
CC = cc
CFLAGS = -O0 -g -Wall

-hello-upgrade: prog.o
-       $(CC) $(CFLAGS) $< -o $@
+hello-upgrade: prog.o fun.o
+       $(CC) $(CFLAGS) $^ -o $@
clean:
       rm -f $(TRASH)

diff --git a/fun.c b/fun.c
new file mode 100644
index 0000000..5460923
--- /dev/null
+++ b/fun.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void return_str(char* str) {
+       snprintf(str, 30, "Hello, Upgraded Packager!");
+}
diff --git a/fun.h b/fun.h
new file mode 100644
index 0000000..444a555
--- /dev/null
+++ b/fun.h
@@ -0,0 +1 @@
+void return_str(char* str);
diff --git a/prog.c b/prog.c
index 5c41659..c05ada9 100644
--- a/prog.c
+++ b/prog.c
@@ -1,8 +1,11 @@
#include <stdio.h>
-
-char str[] = "Hello, Packager!";
+#include <stdlib.h>
+#include "fun.h"

int main(void) {
-       printf("%s\n", str);
+       char* result = malloc(30 * sizeof(char));
+       return_str(result);
+       printf("%s\n", result);
+       free(result);
       return 0;
}
[user@VM hello-upgrade-pkg]$
Теперь откатим репозиторий на коммит до изменений и просто сохраним патч:
@user
[user@VM hello-upgrade-pkg]$ git reset --hard HEAD~
HEAD is now at fa6269f 1.0-alt1
[user@VM hello-upgrade-pkg]$ tree . .gear/
.
├── hello-upgrade-1.0-alt1.patch
├── Makefile
└── prog.c
.gear/
├── hello-upgrade.spec
└── rules

2 directories, 5 files
[user@VM hello-upgrade-pkg]$ git status
On branch master
Untracked files:
 (use "git add <file>..." to include in what will be committed)
       hello-upgrade-1.0-alt1.patch

nothing added to commit but untracked files present (use "git add" to track)
[user@VM hello-upgrade-pkg]$ git add hello-upgrade-1.0-alt1.patch
[user@VM hello-upgrade-pkg]$ vim .gear/hello-upgrade.spec
[user@VM hello-upgrade-pkg]$ gear-commit -a
[master 157f524] 1.0-alt1
2 files changed, 54 insertions(+)
create mode 100644 hello-upgrade-1.0-alt1.patch
[user@VM hello-upgrade-pkg]$
Добавим описание патча в spec-файл и .gear/rules для его переноса в hasher при сборке. В spec-файле необходимо указать название патча, а также команду применения патча после распаковки исходников (в директиву %prep добавляется специальный макрос %autopatch):
@user: hello-upgrade-pkg/.gear/hello-upgrade.spec
Name: hello-upgrade
Version: 1.0
Release: alt1

Summary: Test pkg with patch

License: GPL-3.0-or-later
Group: Development/Other

Source0: %name-%version.tar.gz
Patch: %name-%version-%release.patch

%description
This is a small testing package, builded with patch

%prep
%setup
%autopatch -p1

%build
%make_build

%install
install -D %name %buildroot%_bindir/%name

%files
%_bindir/%name


%changelog
* Sat Aug 02 2025 UsamG1t <usamg1t@altlinux.org> 1.0-alt1
- Initial Build
- Add Patch
При сборке %autopatch раскрывается в последовательное применение патчей, заданных директивами Patch: и Patch№:. Ключ -p1 передаётся каждому запуску утилиты Patch — он означает, что в описании имён файлов внутри патча присутствует один «лишний» каталог. В самом деле, в описании патча, полученного с помощью git diff все изменённые файлы принадлежат псевдодиректориям a/ и b/:
@user
[user@VM hello-upgrade-pkg]$ cat hello-upgrade-1.0-alt1.patch | grep -E "(a/|b/)"
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
diff --git a/fun.c b/fun.c
+++ b/fun.c
diff --git a/fun.h b/fun.h
+++ b/fun.h
diff --git a/prog.c b/prog.c
--- a/prog.c
+++ b/prog.c
[user@VM hello-upgrade-pkg]$
a/ — обозначает «старую» версию файла, b/ — «новую» версию, между которыми производится сравнение. При применении патча эти директории будут проигнорированы утилитой (как раз благодаря флагу -p1), но при этом повышается читаемость самого патча.
Соберём пакет и проверим, что патч применился:
@user
[user@VM hello-upgrade-pkg]$ gear-hsh --lazy
<...>
Executing(%prep): /bin/sh -e /usr/src/tmp/rpm-tmp.84343
+ umask 022
+ /bin/mkdir -p /usr/src/RPM/BUILD
+ cd /usr/src/RPM/BUILD
+ cd /usr/src/RPM/BUILD
+ rm -rf hello-upgrade-1.0
+ echo 'Source #0 (hello-upgrade-1.0.tar.gz):'
Source #0 (hello-upgrade-1.0.tar.gz):
+ /bin/tar -xf -
+ /usr/bin/gzip -dc /usr/src/RPM/SOURCES/hello-upgrade-1.0.tar.gz
+ cd hello-upgrade-1.0
+ /bin/chmod -c -Rf u+rwX,go-w .
+ echo 'Patch #0 (hello-upgrade-1.0-alt1.patch):'
Patch #0 (hello-upgrade-1.0-alt1.patch):
+ /usr/bin/patch -p1
patching file Makefile
patching file fun.c
patching file fun.h
patching file prog.c
+ exit 0
<...>
[user@VM hello-upgrade-pkg]$ cp ~/hasher/repo/x86_64/RPMS.hasher/hello-upgrade-1.0-alt1.x86_64.rpm ~/hasher/chroot/.in/
[user@VM hello-upgrade-pkg]$ hsh-shell --rooter
@rooter
[root@localhost .in]# rpm -i hello-upgrade-1.0-alt1.x86_64.rpm
<13>Aug  3 07:55:29 rpm: hello-upgrade-1.0-alt1 1754206866 installed
[root@localhost .in]# hello-upgrade
Hello, Upgraded Packager!
[root@localhost .in]#