1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
Author: Megver83
Category: GNU/Linux
Date: 2017-07-08 10:02
Image: 2018/04/git-diff.png
Lang: en
Save_as: make-patches-with-git/index.html
URL: make-patches-with-git/
Slug: crear-parches-con-git
Tags: git, diff, patch
Title: Make patches with Git
Many times it happens, especially when working in code development,
that we modify software (eg something as simple as a script or
several files from the source code of a program) and we want to
share that modification or just save it to have that "differentiation"
in the form of a plain text file for later application when the
program on which we are based is updated.
Well that's the role patches play.
Wikipedia says the following about patches:
>A patch is a set of changes to a computer program or its supporting
>data designed to update, fix, or improve it. This includes fixing
>security vulnerabilities and other bugs, with such patches usually
>being called bugfixes or bug fixes, and improving the functionality,
>usability or performance.
Well there are several methods to create patches, the most used
are `diff` and `git diff`. In this tutorial the use of `git diff`
will be taught, as it is more complete.
## First step: create directories
This is a very important step, that most of the tutorials skip,
why will be explained later.
If you look closely, in Git, every time a commit is made a
patch is created, and when it shows a modified file the
command `diff --git a/path/to/file/modified.sh b/path/to/file/modified.sh`
where `modified.sh` is, in this case, a script that was modified (.❛ ᴗ ❛.)
So, to modify our script, text or source code, we must first
create the directory `a` and `b`
:::bash
$ mkdir a b
In directory `a` we will put the unmodified file or files,
and in directory `b` the modified one.
## Step two: create patch
Run:
```bash
$ git diff --no-prefix --no-index --no-renames --binary a b > patched.patch
```
+ --no-prefix: Do not show any source or destination prefix.
+ --no-index: It is used to compare the two paths given in the file system.
+ --no-remanes: Turn off file renaming detection.
+ --binary: Create a binary diff that can be applied with git apply.
You have your patch ready. Simple, right? Well, now is the time to try it.
## Step three: apply patch
Once we have our patch as a `.diff` or `.patch` file (although in general any
extension can be used), we will apply it with `patch` or `git apply`
depending on the case.
1. Plain text only: If your patch only modifies plain text, such as scripts,
C/C ++ source files, Python, Pascal, Javascript, PHP, HMTL, etc.
then we will use this command:
:::bash
$ patch -p1 -i /ruta/del/parche.diff
2. With binary files: That is, things like already compiled executable programs,
PNG images, JPEG, Gif, etc. other than plain text. In general you will be able
to identify when a binary is patched when in patch it says something like
"GIT binary patch". In this case we will apply the patch as follows:
:::bash
$ git apply -v /ruta/del/parche.diff
## The issue with diff and not making directories a and b
Now, going back to what I said earlier about why this is important,
it is because in many guides, wikis, etc. I have found that instead
of creating these directories, they create a file (eg) `script.sh`
and `script.sh.new` and then based on that they run
`diff -u scripts.sh script.sh.new`.
It turns out that there are two problems in this:
+ By doing that, in the patch instead of saying something like
`diff --options a/path/to/file/modified.sh b/path/to/file/modified.sh`
says (in this case) `diff --options script.sh script.sh.new`,
but it turns out that you want to patch `b/script.sh`,
not `script.sh.new` (because inside `b/` are the modified files).
+ If `diff` is used, when it detects a file that didn't originally exist in `a/`
(surely because you created one in `b/`), it won't add it in the patch,
and if you deleted one inside the original tree, it won't remove that file either.
+ `diff` cannot patch binaries.
To better understand it, I will exemplify each case with two examples.
In the first one, I will create the files that I put as an example
(worth the redundancy) and I will use diff:
**script.sh:**
:::bash
#!/bin/bash
echo "Hello world"
**script.sh.new:**
:::sh
#!/bin/sh
echo "Hello world"
echo "This is a patched file :D"
Now we will do what most internet tutorials tell you to do:
:::bash
$ diff -u script.sh script.sh.new
And it looks like this:
:::diff
--- script.sh 2018-03-16 15:52:49.887087539 -0300
+++ script.sh.new 2018-03-16 15:53:02.490420209 -0300
@@ -1,2 +1,3 @@
-#!/bin/bash
+#!/bin/sh
echo "Hello world"
+echo "This is a patched file :D"
Everything apparently fine, but now let's apply that patch
```bash
$ diff -u script.sh script.sh.new | patch -p1 -i /dev/stdin
```
:::diff
can't find file to patch at input line 3
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|--- script.sh 2018-03-16 15:52:49.887087539 -0300
|+++ script.sh.new 2018-03-16 15:53:02.490420209 -0300
--------------------------
File to patch:
It fails being that I am in the same directory as `script.sh{.new}`,
so this is fixed using the create directories `a/` and `b/` hack.
However, this does not turn out point 2 and 3. Let's go for it.
Suppose we have this inside `a/` and `b/`:
a:
script.sh
b:
binary_file.bin script.sh
Okay, now let's make the patch with diff:
```bash
$ diff -ur a b
```
:::diff
Only in b: binary_file.bin
diff -ur a/script.sh b/script.sh
--- a/script.sh 2018-03-16 15:37:27.513802777 -0300
+++ b/script.sh 2018-03-16 15:41:17.717123987 -0300
@@ -1,2 +1,3 @@
-#!/bin/bash
+#!/bin/sh
echo "Hello world"
+echo "This is a patched file :D"
And what is said in point 2 is true, it does not put the new file,
it tells you "Only in b" or if there is a file that is in `a/` but not in `b/`
(that is to say, surely you removed it from your fork), you will
get the message "Only in a" instead of deleting or creating it.
If we apply this patch it will only affect the plain text files,
and even if it did its job and created this new file it would not
work because `binary_file.bin` is a binary, which is not supported
by `diff` but it is supported by `git` which leads us to third point.
See what happens if I use `git` instead of `diff`:
```bash
$ git diff --no-prefix --no-index --no-renames --binary a b
```
:::diff
diff --git b/binary_file.bin b/binary_file.bin
new file mode 100644
index 0000000000000000000000000000000000000000..1ce3c1c596d7a7f400b0cc89bda5a41eed2780c5
GIT binary patch
literal 73
pcmd-HXHZUIU{c}EWl|AfLZWk+R0P|Ad@#)bSHb~R0-{lr003gr3L5|b
literal 0
HcmV?d00001
diff --git a/script.sh b/script.sh
index da049c4..3d351f5 100644
--- a/script.sh
+++ b/script.sh
@@ -1,2 +1,3 @@
-#!/bin/bash
+#!/bin/sh
echo "Hello world"
+echo "This is a patched file :D"
Now I did consider the non-existent binary file in `a/` but tangible in `b/`.
Note that in this particular case, as I explained earlier, when dealing with
binary files that only git supports (see the message "GIT binary patch") you
must use `git apply`. But I recommend using it only when it is mandatory,
not always (in general, not many binaries are used in software that is
100% free, unless they are cases such as firmware for the kernel or
precompiled libraries, but free software blobbeado It usually has proprietary
binaries in its code, although just because it's binary doesn't necessarily
mean it's proprietary.)
If you have doubts about the use of `diff` and `git diff` or patch and `git apply`,
remember that you can leave them in the comments, as well as read their **manpages**
and consult their web pages for more information.
|