Using Patch

Share on:

Overview

While revising for some Kubernetes exams, I realised I havent done a blog post on some useful commands.

The third blog post covers the patch command. For alot of situations patch can be a more straightforward approach to updating similar files. If you are not familiar with patch, it takes the ouput from a diff and adds it to a file. Typically you would use something like sed for a lot of in file manipulation.

In this blog post, I will assume you already know how to use diff. If you dont you will most likely want to read a previous post on how to use diff.

A patch is a file that contains the differences between two versions of a file. You create it using the diff command. The patch command then applies these differences to an older version of a file, transforming it into the newer version. This is useful for distributing changes to code or configuration files without having to send the entire file. It's efficient because only the modifications are transmitted.

Creating a patch file:

  1. Use the diff command: The core of creating a patch is the diff command. Its basic syntax is:

    1diff [options] original_file modified_file > patch_file.patch
    
    • original_file: The original, unmodified file.
    • modified_file: The modified version of the file.
    • >: This redirects the output of the diff command (the patch data) into a new file.
    • patch_file.patch: The name you choose for your patch file. It's convention to use the .patch extension.
  2. Choose appropriate options: The diff command has several options that control the format and content of the patch file. Here are the most common and useful ones:

    • -u or -unified: Creates a "unified diff" which is the most common and preferred format. It provides context lines around the changes, making it easier to apply the patch even if the target file has been slightly modified. This is highly recommended.

      1diff -u original_file modified_file > patch_file.patch
      
    • -N or --new-file: Treats absent files as empty. Essential when adding a new file.

    • -r or --recursive: Recursively compare directories. Useful when creating patches for entire directory trees.

    • -a or --text: Treat all files as text. This is useful if diff incorrectly identifies a file as binary.

    • -x <pattern> or --exclude=<pattern>: Exclude files matching a pattern. For example, -x "*.o" would exclude object files. Useful with -r.

    • -i or --ignore-case: Ignores case differences in the files.

    • -w or --ignore-all-space: Ignores all whitespace.

    • -B or --ignore-blank-lines: Ignores changes where lines are all blank.

    • --strip-trailing-cr: Strip any trailing carriage return on input.

  3. Example: Let's say you have an original file named myfile.txt and you've made changes, saving it as myfile_modified.txt. To create a unified patch file, you would use:

    1diff -u myfile.txt myfile_modified.txt > myfile.patch
    
  4. Directory diffs: If you need to create a patch for an entire directory, use the -r option. It's good practice to create the patch from the top-level directory that contains both versions of the directory you are diffing. For example, if you have directory trees original_dir and modified_dir, where original_dir is a copy of the original code and modified_dir is the modified code:

    1diff -ur original_dir modified_dir > mydirectory.patch
    

    Important: When creating directory diffs, the paths stored inside the patch file are relative to the paths provided to the diff command. This is critical for applying the patch correctly. If original_dir and modified_dir have different parent directories, you'll need to adjust the --strip option when applying the patch (explained in the "Applying the Patch" section).

  5. Verifying the patch file: After creating the .patch file, it's a good idea to examine it with a text editor or less or cat to confirm it contains the changes you expect and that the file paths are correct. Pay close attention to lines that begin with --- (original file) and +++ (modified file) as they specify the filenames the patch will affect. The lines starting with @@ indicate the line numbers where changes will be applied along with the context around them.

Patch file walkthrough

  1. Create Original File: Let's start with a simple original file named original.txt:

    1echo "This is the original file." > original.txt
    2echo "It contains some text." >> original.txt
    3echo "This is line three." >> original.txt
    
  2. Create Modified File: Now, modify the file slightly. For example, change the first line and add a new line at the end. Let's call this modified.txt:

    1echo "This is the modified original file." > modified.txt
    2echo "It contains some text." >> modified.txt
    3echo "This is line three." >> modified.txt
    4echo "This is the new line." >> modified.txt
    
  3. Generate the Diff File: Use diff to create the patch file. The -u option creates a unified diff, which is generally preferred:

    1diff -u original.txt modified.txt > mypatch.patch
    

    Examine the contents of mypatch.patch. It will look something like this:

    1--- original.txt    2023-10-27 14:30:00.000000000 -0400
    2+++ modified.txt    2023-10-27 14:30:30.000000000 -0400
    3@@ -1,3 +1,4 @@
    4-This is the original file.
    5+This is the modified original file.
    6 It contains some text.
    7 This is line three.
    8+This is the new line.
    
    • --- original.txt: Indicates the original file.
    • +++ modified.txt: Indicates the modified file.
    • @@ -1,3 +1,4 @@: This is the hunk header. -1,3 means "starting at line 1, 3 lines are being removed/changed from the original file". +1,4 means "starting at line 1, 4 lines are being added/changed in the modified file".
    • -: Lines prefixed with a minus sign are being removed.
    • +: Lines prefixed with a plus sign are being added.
    • : Lines prefixed with a space are unchanged lines providing context.
  4. Apply the Patch: Now, let's revert the modified.txt file back to the original. Then, apply the patch to original.txt:

    1cp original.txt modified.txt #Reset modified.txt to be same as original.txt.
    2patch original.txt mypatch.patch
    
  5. Verify the Result: Check the contents of original.txt. It should now match the contents of modified.txt after patching:

    1cat original.txt
    

    Output:

    1This is the modified original file.
    2It contains some text.
    3This is line three.
    4This is the new line.
    
  6. Reverse Patching (Optional): You can also reverse the patch. This is useful if you accidentally applied a patch and want to undo it. Use the -R option:

    1patch -R original.txt mypatch.patch
    

    Now, original.txt should be back to its original state. You can verify this with cat original.txt.

Important Considerations:

  • File Paths: patch often uses the file paths stored within the patch file itself. The -p option is crucial for telling patch how many directory levels to strip from the pathnames in the patch file. If the patch fails, experiment with -p0, -p1, -p2, etc. to find the correct level. The correct level depends on how the diff was generated relative to where you are applying it. The most common value is -p1.

  • Backup Files: By default, patch creates backup files (usually with a .orig extension) of the original files before patching. You can disable this behavior with the -N option.

  • Dry Run: Use the -N option for a dry run. This will show you what changes patch would make without actually modifying any files.

  • Fuzz: Sometimes, the context lines in the patch file don't exactly match the original file. This can happen if the original file has been slightly modified since the patch was created. patch has a "fuzz factor" that allows it to tolerate some differences. You can control the fuzz factor with the -F option, but it's generally best to avoid using fuzz unless absolutely necessary.

Conclusion

The diff and patch utilities provide a robust and efficient way to distribute and apply changes to text-based files.

Understanding how to create and apply patches can streamline collaboration, simplify updates, and manage configuration changes effectively. Remember to thoroughly test patches after application to ensure the changes have been applied correctly and haven't introduced any unintended side effects. By mastering these tools, you can significantly improve your workflow when working with code and configuration files in a collaborative or version-controlled environment.