如何为整个目录创建更新补丁?

我知道已经有几个线程在讨论这个问题,但是没有人完全解释如何执行初始 diff 来创建补丁文件,然后如何将该补丁 申请到初始目录来更新它。

在我的例子中,有一个文件目录,任何人都可以从网上下载。我已经获取了那个目录并对其进行了更改,并希望创建一个补丁文件,以便其他人可以将其应用到下载的目录中,从而完全复制我修改后的目录中的内容。

帮助? 关于如何应用我的补丁,我需要告诉其他人什么?

104120 次浏览

I just had this same problem - lots of advice on how to half do it. Well, here is what I did to get both the patching and unpatching to work:

To Create the Patch File:

  1. Put copies of both directories in say /tmp, so we can create the patch file, or if brave, get them side by side - in one directory.

  2. Run an appropriate diff on the two directories, old and new:

    diff -ruN orig/ new/ > file.patch
    # -r == recursive, so do subdirectories
    # -u == unified style, if your system lacks it or if recipient
    #       may not have it, use "-c"
    # -N == treat absent files as empty
    

If a person has the orig/ directory, they can recreate the new one by running patch.

To Recreate the new folder from old folder and patch file:

  1. Move the patch file to a directory where the orig/ folder exists

  2. This folder will get clobbered, so keep a backup of it somewhere, or use a copy.

    patch -s -p0 < file.patch
    # -s == silent except errors
    # -p0 == needed to find the proper folder
    
  3. At this point, the orig/ folder contains the new/ content, but still has its old name, so:

    mv orig/ new/    # if the folder names are different
    

Check out open source Scarab C++ library: https://github.com/loyso/Scarab

It does exactly what you described. It builds per-file diff using xdelta library and puts it to archive package. You can redistribute that package and apply the difference. There are binaries for Win32.

I'm the author of Scarab project.

I needed to create a patch file and send it to someone so they could update their directory to match mine. There are many caveats with diff and patch however, so it ended up taking me hours to figure out something so conceptually simple. Absolute paths seem to be preferred over relative paths, and many of the options seem to have evolved from niche use cases. I finally figured out a solution based on David H's answer, with additional tips from Lakshmanan Ganapathy):

  • Back up your directory to directory.orig
  • Modify your directory to reach the desired state
  • Save diff from directory.orig to directory in file.patch so name matches for recipient

Here are my notes:

# to create patch:
# copy <directory> backup to something like <directory>.orig alongside it
cp -r <path_to>/<directory> <path_to>/<directory>.orig
# create/update/delete files/folders in <directory> until desired state is reached
# change working directory to <directory>
cd <path_to>/<directory>
# create patch file alongside <directory>
diff -Naru ../<directory>.orig . > ../file.patch
# -N --new-file Treat absent files as empty.
# -a --text Treat all files as text.
# -r --recursive Recursively compare any subdirectories found.
# -u -U NUM --unified[=NUM] Output NUM (default 3) lines of unified context.


# to apply patch:
# change working directory to <directory>
cd <path_to>/<directory>
patch -s -p0 < <path_to>/file.patch
# -s or --silent or --quiet Work silently, unless an error occurs.
# -pN or --strip=N Strip smallest prefix containing num leading slashes from files.


# to undo patch (note that directories created by patch must be removed manually):
# change working directory to <directory>
cd <path_to>/<directory>
patch -Rs -p0 < <path_to>/file.patch
# -R or --reverse Assume that patch was created with the old and new files swapped.
# -s or --silent or --quiet Work silently, unless an error occurs.
# -pN or --strip=N Strip smallest prefix containing num leading slashes from files.