使用patch给代码打补丁,快速高效、patch -p1 和p0 的区别

本文深入讲解了Patch与Diff命令的使用方法,包括如何生成和应用补丁,以及各种参数的含义。通过具体实验,展示了不同目录层级下使用Patch命令的区别,帮助读者掌握补丁制作与应用的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 生成patch:
git diff > file.patch
  • 打patch:
patch -p1 < file.patch
git apply file.patch
说到patch命令,就不得不提到diff命令,也就是制作patch的必要工具。diff命令,在制作patch文件的时候,基本上只需要使用到diff -Nau 这个参数,如果比较的是文件夹,还要加上-r参数,所以一般直接使用Naur参数。

实验的基本步骤。我打算是建立一个级联目录./x/xx/xxx/,在xxx目录下建立两个不同的文件xxx1,xxx2。然后在xxx目录下用diff命令,建立一个补丁文件xxx.patch,在xx目录下建立一个补丁文件xx.patch,在x目录下建立一个补丁文件x.patch。然后在这三个目录下实验。

开始实验:建立实验目录
[King@Fedora ~]$ mkdir -pv x/xx/xxx
mkdir: 已创建目录 “x”
mkdir: 已创建目录 “x/xx”
mkdir: 已创建目录 “x/xx/xxx”

进入xxx目录下创建xxx1,xxx2

[King@Fedora ~]$ cd x/xx/xxx
[King@Fedora xxx]$ cat >> xxx1 << EOF
> 111111
> 111111
> EOF
[King@Fedora xxx]$ cat >> xxx2 << EOF
> 111111
> 222222
> EOF

查看这两个文件:

[King@Fedora xxx]$ diff -y xxx1 xxx2
111111                                111111
111111                           |    222222

一定要注意:打补丁时所在的目录

在xxx目录下创建补丁文件xxx.patch,并查看。
[King@Fedora xxx]$ diff -Naru xxx1 xxx2 > xxx.patch
[King@Fedora xxx]$ cat xxx.patch 
- - - xxx1    2009-12-19 22:28:26.582959182 +0800
+++ xxx2    2009-12-19 22:28:42.798928591 +0800
@@ -1,2 +1,2 @@
  111111
- 111111
+222222

在xx目录下创建补丁文件xx.patch,并查看:

[King@Fedora xxx]$ cd ..
[King@Fedora xx]$ diff -Naru xxx/xxx1 xxx/xxx2 > xx.patch
[King@Fedora xx]$ cat xx.patch 
--- xxx/xxx1    2009-12-19 22:28:26.582959182 +0800
+++ xxx/xxx2    2009-12-19 22:28:42.798928591 +0800
@@ -1,2 +1,2 @@
111111
-111111
+222222

在x目录下创建补丁文件x.patch,并查看

[King@Fedora xx]$ cd ..
[King@Fedora x]$ diff -Nu xx/xxx/xxx1 xx/xxx/xxx2 > x.patch
[King@Fedora x]$ cat x.patch 
--- xx/xxx/xxx1    2009-12-19 22:28:26.582959182 +0800
+++ xx/xxx/xxx2    2009-12-19 22:28:42.798928591 +0800
@@ -1,2 +1,2 @@
111111
-111111
+222222

现将patch文件都拷贝到xxx目录下去。

[King@Fedora x]$ cp x.patch xx/xxx/
[King@Fedora x]$ cp xx/xx.patch xx/xxx/

进入xxx目录开始实验

[King@Fedora x]$ cd xx/xxx
[King@Fedora xxx]$ ls
x.patch  xx.patch  xxx1  xxx2  xxx.patch
[King@Fedora xxx]$ patch-p0< xxx.patch  #用第二个的 补丁 修改 第一个文件
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
222222
[King@Fedora xxx]$ patch -RE < xxx.patch #用第一个的 补丁 修改 第一个文件
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
111111
[King@Fedora xxx]$ patch -p1 < xx.patch
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
222222
[King@Fedora xxx]$ patch -RE < xxx.patch
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
111111
[King@Fedora xxx]$ patch -p2 < x.patch
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
222222
[King@Fedora xxx]$ patch -RE < x.patch
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
111111
[King@Fedora xx]$ patch-p0 < xx.patch  # 用第二个的 补丁 修改 第一个文件
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
222222
[King@Fedora xxx]$ patch -RE < xxx.patch #用第一个的 补丁 修改 第一个文件
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
111111

[King@Fedora xxx]$ patch -p1 < x.patch
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
222222
[King@Fedora xxx]$ patch -RE < xxx.patch
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
111111
[King@Fedora x]$ patch-p0< x.patch  # 用第二个的 补丁 修改 第一个文件
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
222222
[King@Fedora xxx]$ patch -RE < xxx.patch #用第一个的 补丁 修改 第一个文件
patching file xxx1
[King@Fedora xxx]$ cat xxx1
111111
111111

这里唯一需要说明的是p0的含义,因为在x.patch补丁文件里的路径信息是这样的:

--- xx/xxx/xxx1   

**p表示跳过几级目录.**因为是在x目录下使用的patch命令,xx目录就在x目录下,所以不必跳过任何目录,而应该使用— xx/xxx/xxx1 完整路径,所以此时使用的是p0。

注意:patch -p后面是不能带负数 的。不使用p参数的时候,patch命令会 忽略 任何目录,直接使用文件。

[King@Fedora x]$ patch x/xx/xxx/xxx1 < x.patch # 用补丁x.patch 直接修改 文件xxx1,因为没有用p参数,所以 会 忽略掉补丁文件里的 所有目录。

作为程序员,了解diff&patch命令是非常必要的。比如说我们发现某个项目有bug代码,而自己又没有提交权限,那么此时最合适的解决方法就是用diff命令做一个补丁发给项目成员。项目成员通过patch命令可以立刻知道你的意图。有人会说直接传一个新文件不是更简单?不要忘了,一个patch文件尺寸更小传输更快,而且可以明显的看到都做了哪些修改。

例子保证当前目录是demo名录:

mkdir demo
cd demo

先模拟一个项目目录old:

mkdir -p old/a/b
vi old/a/b/foo.txt
old_line_1
old_line_2

假设我们发现项目old有bug代码,下面我们先拷贝一个新目录new,并在此修改bug代码:

cp -r old new
vi new/a/b/foo.txt
new_line_1
new_line_2

保证old和new两个目录都在当前目录下,下面就可以使用diff命令了,不要使用绝对路径,而应该使用相对路径,至于原因,看到文章结尾你就清楚了:

LC_ALL=C TZ=UTC0 diff -Naur old new > foo.patch

如果不在意字符集,时差等问题,也可以省略LC_ALL=C TZ=UTC0环境变量:

diff -Naur old new > foo.patch

内容来自Linuxren.net
其中-Naur参数属于固定用法,大多数时候,在使用diff命令时搭配这个参数就可以了。

大概浏览一下补丁文件:

cat foo.patch
diff -Naur old/a/b/foo.txt new/a/b/foo.txt
--- old/a/b/foo.txt     2009-12-07 20:40:07.000000000 +0800
+++ new/a/b/foo.txt     2009-12-07 20:41:51.000000000 +0800
@@ -1,2 +1,2 @@
-old_line_1
-old_line_2
+new_line_1
+new_line_2

加减号后面的内容是有用的内容,其他的内容是方便你查阅的相关信息内容,补丁制作完成。
此时的文件目录结构大概如下所示:

#tree
demo
|-- old
|   `-- a
|       `-- b
|           `-- foo.txt
|-- new
|   `-- a
|       `-- b
|           `-- foo.txt 
-- foo.patch

下面看看如何使用patch来应用补丁,要注意的是当前目录是demo,试试下面命令:

 patch -p0 < foo.patch
patching file old/a/b/foo.txt

这里唯一需要说明的是p0的含义,因为在foo.patch补丁文件里的路径信息是这样的:

--- old/a/b/foo.txt

p表示跳过几级目录,因为是在demo目录下使用的patch命令,old目录就在demo目录下,所以不必跳过任何目录,而应该使用old/a/b/foo.txt完整路径,所以此时使用的是p0。

查看一下目标文件,你会发现内容已经修改成新的了:

# cat old/a/b/foo.txt
new_line_1
new_line_2

此时如果你再次使用patch命令,系统会问你是否想还原,输入y 还原:

# patch -p0 < foo.patch
patching file old/a/b/foo.txt
Reversed (or previously applied) patch detected!  Assume -R? [n] y

查看一下目标文件,你会发现内容已经还原成旧的了:

# cat old/a/b/foo.txt
old_line_1
old_line_2

如果你想严格指定是 应用补丁 可以使用下面命令(就是增加N参数):

# patch -Np0 < foo.patch

如果你想严格指定是 还原补丁 可以使用下面命令(就是增加R参数):

# patch -Rp0 < foo.patch

注释:在本例中,每次应用补丁后,自己还原补丁,以备后用继续试验,我就不多说了。

看到这里如果你对patch的p参数还不太清楚的话,接着往下看,我们改变一下当前路径:

# cd old

此时就应该是p1,而不是p0了,引用foo.patch文件的路径也要相对变一下,因为当前目录已经是old了: Linuxren.net

# patch -p1 < ../foo.patch
patching file a/b/foo.txt

因为此时我们是在old下使用patch命令,和a子目录平级,而补丁文件foo.patch里的路径声明是:

--- old/a/b/foo.txt

也就是说第一个斜线左边的old/部分已经没用了,这就是p1的含义!
继续往深度变换路径,依次测试使用p2,p3参数:

# cd a
# patch -p2 < ../../foo.patch
patching file b/foo.txt
# cd b
# patch -p3 < ../../../foo.patch
patching file foo.txt

在本例中,p3已经是最深目录了,此时可以省略p参数:

# patch < ../../../foo.patch
patching file foo.txt

也就是说,不使用p参数的时候,patch命令会 忽略 任何目录,直接使用文件。

下面接着文章前面说的为什么使用diff命令时最好不要使用绝对路径,而应该使用相对路径?

答:如果你在使用diff的时候使用的是绝对路径,那么补丁文件里的文件路径信息会类似下面的样子:

--- /a/b/c/d/e/f/g/bar.txt
	如此一来,当别人想应用你的补丁时,因为目录结构肯定有差异,所以就不得不费力判断到底使用p几。这样一来就很容易出错,相反,如果使用相对路径的话,大多数时候,p0或者p1就足够了,不易出错。

百度百科得出的一些用途解释:
Linux diff命令用于比较文件的差异:
diff以逐行的方式,比较文本文件的异同处。如果指定要比较目录,则diff会比较目录中相同文件名的文件,但不会比较其中子目录。

语法
diff [-abBcdefHilnNpPqrstTuvwy][-<行数>][-C <行数>][-D <巨集名称>][-I <字符或字符串>][-S <文件>][-W <宽度>][-x <文件或目录>][-X <文件>][–help][–left-column][–suppress-common-line][文件或目录1][文件或目录2]
参数:

-<行数>  指定要显示多少行的文本。此参数必须与-c或-u参数一并使用。-a或–text  diff预设只会逐行比较文本文件。-b或–ignore-space-change  不检查空格字符的不同。

-B或–ignore-blank-lines  不检查空白行。
-c  显示全部内文,并标出不同之处。
-C<行数>或–context<行数>  与执行"-c-<行数>"指令相同。
-d或–minimal  使用不同的演算法,以较小的单位来做比较。
-D<巨集名称>或ifdef<巨集名称>  此参数的输出格式可用于前置处理器巨集。
-e或–ed  此参数的输出格式可用于ed的script文件。
-f或-forward-ed  输出的格式类似ed的script文件,但按照原来文件的顺序来显示不同处。
-H或–speed-large-files  比较大文件时,可加快速度。
-l<字符或字符串>或–ignore-matching-lines<字符或字符串>  若两个文件在某几行有所不同,而这几行同时都包含了选项中指定的字符或字符串,则不显示这两个文件的差异。
-i或–ignore-case  不检查大小写的不同。
-l或–paginate  将结果交由pr程序来分页。
-n或–rcs  将比较结果以RCS的格式来显示。
-N或–new-file  在比较目录时,若文件A仅出现在某个目录中,预设会显示:
Only in目录:文件A若使用-N参数,则diff会将文件A与一个空白的文件比较。
-p  若比较的文件为C语言的程序码文件时,显示差异所在的函数名称。
-P或–unidirectional-new-file  与-N类似,但只有当第二个目录包含了一个第一个目录所没有的文件时,才会将这个文件与空白的文件做比较。
-q或–brief  仅显示有无差异,不显示详细的信息。
-r或–recursive  比较子目录中的文件。
-s或–report-identical-files  若没有发现任何差异,仍然显示信息。
-S<文件>或–starting-file<文件>  在比较目录时,从指定的文件开始比较。
-t或–expand-tabs  在输出时,将tab字符展开。
-T或–initial-tab  在每行前面加上tab字符以便对齐。
-u,-U<列数>或–unified=<列数>  以合并的方式来显示文件内容的不同。
-v或–version  显示版本信息。
-w或–ignore-all-space  忽略全部的空格字符。
-W<宽度>或–width<宽度>  在使用-y参数时,指定栏宽。
-x<文件名或目录>或–exclude<文件名或目录>  不比较选项中所指定的文件或目录。
-X<文件>或–exclude-from<文件>  您可以将文件或目录类型存成文本文件,然后在=<文件>中指定此文本文件。
-y或–side-by-side  以并列的方式显示文件的异同之处。
–help  显示帮助。
–left-column  在使用-y参数时,若两个文件某一行内容相同,则仅在左侧的栏位显示该行内容。
–suppress-common-lines  在使用-y参数时,仅显示不同之处。

Linux patch命令用于修补文件。
patch指令让用户利用设置修补文件的方式,修改,更新原始文件。倘若一次仅修改一个文件,可直接在指令列中下达指令依序执行。如果配合修补文件的方式则能一次修补大批文件,这也是Linux系统核心的升级方法之一。

语法
patch [-bceEflnNRstTuvZ][-B <备份字首字符串>][-d <工作目录>][-D <标示符号>][-F <监别列数>][-g <控制数值>][-i <修补文件>][-o <输出文件>][-p <剥离层级>][-r <拒绝文件>][-V <备份方式>][-Y <备份字首字符串>][-z <备份字尾字符串>][–backup-if -mismatch][–binary][–help][–nobackup-if-mismatch][–verbose][原始文件 <修补文件>] 或 path [-p <剥离层级>] < [修补文件]
参数:

-b或–backup  备份每一个原始文件。
-B<备份字首字符串>或–prefix=<备份字首字符串>  设置文件备份时,附加在文件名称前面的字首字符串,该字符串可以是路径名称。
-c或–context  把修补数据解译成关联性的差异。
-d<工作目录>或–directory=<工作目录>  设置工作目录。
-D<标示符号>或–ifdef=<标示符号>  用指定的符号把改变的地方标示出来。
-e或–ed  把修补数据解译成ed指令可用的叙述文件。
-E或–remove-empty-files  若修补过后输出的文件其内容是一片空白,则移除该文件。
-f或–force  此参数的效果和指定"-t"参数类似,但会假设修补数据的版本为新 版本。
-F<监别列数>或–fuzz<监别列数>  设置监别列数的最大值。
-g<控制数值>或–get=<控制数值>  设置以RSC或SCCS控制修补作业。
-i<修补文件>或–input=<修补文件>  读取指定的修补问家你。
-l或–ignore-whitespace  忽略修补数据与输入数据的跳格,空格字符。
-n或–normal  把修补数据解译成一般性的差异。
-N或–forward  忽略修补的数据较原始文件的版本更旧,或该版本的修补数据已使 用过。
-o<输出文件>或–output=<输出文件>  设置输出文件的名称,修补过的文件会以该名称存放。
-p<剥离层级>或–strip=<剥离层级>  设置欲剥离几层路径名称。
-f<拒绝文件>或–reject-file=<拒绝文件>  设置保存拒绝修补相关信息的文件名称,预设的文件名称为.rej。
-R或–reverse  假设修补数据是由新旧文件交换位置而产生。
-s或–quiet或–silent  不显示指令执行过程,除非发生错误。
-t或–batch  自动略过错误,不询问任何问题。
-T或–set-time  此参数的效果和指定"-Z"参数类似,但以本地时间为主。
-u或–unified  把修补数据解译成一致化的差异。
-v或–version  显示版本信息。
-V<备份方式>或–version-control=<备份方式>  用"-b"参数备份目标文件后,备份文件的字尾会被加上一个备份字符串,这个字符串不仅可用"-z"参数变更,当使用"-V"参数指定不同备份方式时,也会产生不同字尾的备份字符串。
-Y<备份字首字符串>或–basename-prefix=–<备份字首字符串>  设置文件备份时,附加在文件基本名称开头的字首字符串。
-z<备份字尾字符串>或–suffix=<备份字尾字符串>  此参数的效果和指定"-B"参数类似,差别在于修补作业使用的路径与文件名若为src/linux/fs/super.c,加上"backup/"字符串后,文件super.c会备份于/src/linux/fs/backup目录里。
-Z或–set-utc  把修补过的文件更改,存取时间设为UTC。
–backup-if-mismatch  在修补数据不完全吻合,且没有刻意指定要备份文件时,才备份文件。
–binary  以二进制模式读写数据,而不通过标准输出设备。
–help  在线帮助。
–nobackup-if-mismatch  在修补数据不完全吻合,且没有刻意指定要备份文件时,不要备份文件。
–verbose  详细显示指令的执行过程

### P2T Model Patch Embedding Implementation and Usage In the context of computer vision tasks, the P2T (Patch to Token) model employs a unique approach towards handling image data through its patch embedding mechanism. The primary function of this component is to convert input images into tokens that can be effectively processed by transformer architectures. The process begins with dividing an input image into non-overlapping patches. Each patch undergoes linear projection followed by position encoding addition which helps retain spatial information within each token generated from these patches: ```python import torch from einops import rearrange class PatchEmbedding(torch.nn.Module): def __init__(self, img_size=224, patch_size=16, embed_dim=768): super().__init__() self.img_size = img_size self.patch_size = patch_size num_patches = (img_size // patch_size)**2 self.projection = torch.nn.Conv2d(3, embed_dim, kernel_size=patch_size, stride=patch_size) def forward(self, x): B, C, H, W = x.shape assert H == W == self.img_size, f"Input size must match {self.img_size}" # Projecting patches using convolutional layer x = self.projection(x).flatten(2).transpose(1, 2) return x ``` This method ensures efficient conversion while preserving essential features required for downstream tasks such as classification or object detection. Additionally, incorporating positional encodings allows transformers to understand relative positions between different parts of the image during processing stages[^1]. Furthermore, when applying models like P2T on specific datasets involving temporal sequences—such as EEG signals—the importance of local behavior becomes evident. For instance, studies have shown that shorter segments yield better performance compared to longer ones due to their localized characteristics being more pronounced [^2]. This highlights how critical it is to design embeddings capable of capturing both global structure and fine-grained details present in various types of visual inputs.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值