written by Eric J. Ma on 2018-06-17 | tags: git version control code snippets
I learned a new thing this weekend: we apparently can apply a patch onto a branch/fork using git apply [patchfile]
.
There's a few things to unpack here. First off, what's a patchfile
?
The long story cut short is that a patchfile
is nothing more than a plain text file that contains all information about diffs
between one commit and another. If you've ever used the git diff
command, you'll know that it will output a diff
between the current state of a repository, and the last committed state. Let's take a look at an example.
Say we have a file, called my_file.txt
. In a real world example, this would be parallel to, say, a .py
module that you've written. After a bunch of commits, I have a directory structure that looks like this:
$ ls total 8 drwxr-xr-x 4 ericmjl staff 128B Jun 17 10:26 ./ drwx------@ 19 ericmjl staff 608B Jun 17 10:26 ../ drwxr-xr-x 12 ericmjl staff 384B Jun 17 10:27 .git/ -rw-r--r-- 1 ericmjl staff 68B Jun 17 10:26 my_file.txt
The contents of my_file.txt
are as follows:
$ cat my_file.txt Hello! This is a text file. I have some text written inside here.
Now, let's say I edit the text file by adding a new line and removing one line.
$ cat my_file.txt Hello! This is a text file. I have some text written inside here. This is a new line!
If I looked at the "diff" between the current state of the file and the previous committed state of the file:
$ git diff my_file.txt diff --git a/my_file.txt b/my_file.txt index a594a37..d8602e1 100644 --- a/my_file.txt +++ b/my_file.txt @@ -1,4 +1,4 @@ Hello! This is a text file. -I have some text written inside here. +This is a new line!
While this may look intimidating at first, the key thing that one needs to look at is the +
and -
. The +
signals that there is an addition of one line, and the -
signals the removal of one line.
Turns out, I can export this as a file.
$ git diff my_file.txt > /tmp/patch1.txt $ cat /tmp/patch1.txt diff --git a/my_file.txt b/my_file.txt index a594a37..d8602e1 100644 --- a/my_file.txt +++ b/my_file.txt @@ -1,4 +1,4 @@ Hello! This is a text file. -I have some text written inside here. +This is a new line!
Now, let's simulate the scenario where I accidentally discarded those changes in the repository. A real-world analogue happened to me while contributing to CuPy: I had a really weird commit history, and couldn't remember how to rebase, so I exported the patch from my GitHub pull request (more on this later) and applied it following the same conceptual steps below.
$ git checkout -- my_file.txt
Now, the repository is in a "cleaned" state -- there are no changes made:
$ git status On branch master nothing to commit, working tree clean
Since I have saved the diff as a file, I can apply it onto my project:
$ git apply /tmp/patch1.txt $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: my_file.txt no changes added to commit (use "git add" and/or "git commit -a")
Looking at the diff again, I've recovered the changes that were lost!
$ git diff diff --git a/my_file.txt b/my_file.txt index a594a37..d8602e1 100644 --- a/my_file.txt +++ b/my_file.txt @@ -1,4 +1,4 @@ Hello! This is a text file. -I have some text written inside here. +This is a new line!
Don't forget to commit and push!
I mentioned earlier that I had exported the patch file from GitHub and then applied it on a re-forked repository. How does one do that? It's not as hard as you think.
Here's the commands below with comments.
# Download the patch from the pull request URL. # Replace curly-braced elements with the appropriate names. # Export it to /tmp/patch.txt. $ wget https://github.com/{repo_owner}/{repo}/pull/{pr_number}.patch -O /tmp/patch.txt # Now, apply the patch to your project $ git apply /tmp/patch.txt
@article{
ericmjl-2018-git-patch,
author = {Eric J. Ma},
title = {Git Tip: Apply a Patch},
year = {2018},
month = {06},
day = {17},
howpublished = {\url{https://ericmjl.github.io}},
journal = {Eric J. Ma's Blog},
url = {https://ericmjl.github.io/blog/2018/6/17/git-tip-apply-a-patch},
}
I send out a newsletter with tips and tools for data scientists. Come check it out at Substack.
If you would like to sponsor the coffee that goes into making my posts, please consider GitHub Sponsors!
Finally, I do free 30-minute GenAI strategy calls for teams that are looking to leverage GenAI for maximum impact. Consider booking a call on Calendly if you're interested!