230 lines
7.8 KiB
Markdown
230 lines
7.8 KiB
Markdown
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.
|