regexps.com
It is often extremely useful to compare two project trees (usually for the same project) and figure out exactly what has changed between them. A record of such changes is called a patch set or a delta .
If you have a patch set between an "old tree" and a "new tree", you can "apply the patch" to the old tree to get the new tree -- in other words, you can automatically make the editting changes described by a patch set. If you have some third tree, you can apply the patch to get an approximation of making the same changes to that third tree. (see The Theory of Patches and Revisions).
arch
includes sophisticated tools for creating and applying patch sets.
mkpatch
computes a patch set describing the differences between two
trees. The basic command syntax is:
% mkpatch ORIGINAL MODIFIED DESTINATION
which compares the trees ORIGINAL
and MODIFIED
.
mkpatch
creates a new directory, DESTINATION
, and stores the patch
set there.
When mkpatch
compares trees, it uses inventory tags. For example,
it considers two directories or two files to be "the same directory
(or file)" if they have the same tag -- regardless of where each is
located in its respective tree.
A patch set produced by mkpatch
describes what files and directories
have been added or removed, which have been renamed, which files have
been changed (and how they have been changed), and what file
permissions have changed (and how). When regular text files are
compared, mkpatch
produces a context diff describing the
differences. mkpatch
can compare binary files (saving complete
copies of the old and new versions if they differ) and symbolic links
(saving the old and new link targets, if they differ).
A detailed description of the format of a patch set is provided in an appendix (see The arch Patch Set Format).
dopatch
is used to apply a patch set to tree:
% dopatch patch-set tree
If tree
is exactly the same as the the "original" tree seen by
mkpatch
, then the effect is to modify tree
so that it is exactly
the same as the the "modified" tree seen by mkpatch
, with one
exception (explained below).
"Exactly the same" means that the directory structure is the same, symbolic link targets are the same, the contents of regular files are the same, and file permissions are the same. Modification times, files with multiple (hard) links, and file ownership are not reliably preserved.
The exception to the "exactly the same" rule is that if the patch
requires that files or directories be removed from tree
, those files
and directories will be saved in a subdirectory of tree
with an
eye-splitting name matching the pattern:
++removed-by-dopatch-PATCH--DATE
where PATCH
is the name of the patch-set directory and DATE
a
timestamp.
At this time, dopatch
does not support reverse patching, though this
is likely to be added in a future release.
What if a tree patched by dopatch
is not exactly the same as the
original tree seen by mkpatch
?
Below is a brief description of what to expect. Complete
documentation of the dopatch
process is included with the source
code.
dopatch
takes an inventory of the tree being patched. It uses
inventory tags to decide which files and directories expected by the
patch set are present or missing from the tree, and to figure out
where each file and directory is located in the tree.
Simple Patches If the patch set contains an ordinary patch or
metadata patch for a link, directory or file, and that file is present
in the tree, dopatch
applies the patch in the ordinary way. If the
patch applies cleanly, the modified file, link, or directory is left
in place.
If a simple patch fails to apply cleanly, dopatch
will always leave
behind a .orig
file (the file originally in the tree being patched,
without any changes) and a .rej
file (the part of the patch that
could not be applied).
If the patch was a context diff, dopatch
will also leave behind the
file itself -- partially patched.
If an (unsucessful) patch was for a binary file, no partially-patched file will be left. Instead, there will be:
.orig -- the file originally in the tree being patched, without modifications.
.rej -- a complete copy of the file from the modified tree, with permissions copied from `.orig'.
.patch-orig -- a complete copy of the file from the original tree seen by `mkpatch', with permissions retained from that original
-or-
the symbolic link from the original tree seen by `mkpatch' with permissions as in the original tree.
If an (unsucessful) patch was for a symbolic link, no partially patched file will be left. Instead there will be:
.orig -- the unmodified file from the original tree
.rej -- a symbolic link with the target intended by the patch and permissions copied from .orig
.patch-orig -- a complete copy of the file from the original tree seen by `mkpatch', with permissions retained from that original
-or-
the symbolic link from the original tree seen by `mkpatch' with permissions as in the original tree.
Patches for Missing Files
All patches for missing files and directories are stored in a subdirectory of the root of the tree being patched called
==missing-file-patches-PATCH-DATE
where PATCH
is the basename of the patch set directory and DATE
a
time-stamp.
Directory Rearrangements and New Directories
Directories are added, deleted, and rearranged much as you would expect, even if you don't know it's what you'd expect.
Suppose that when mkpatch
was called the ORIGINAL
tree had:
Directory or file: Tag:
a/x.c tag_1 a/bar.c tag_2
but the MODIFIED
tree had:
a/x.c tag_1 a/y.c tag_2
with changes to both files. The patch will want to rename the file
with tag tag_2
to y.c
, and change the contents of the files with
tags tag_1
and tag_2
.
Suppose, for example, that you have a tree with:
a/foo.c tag_1 a/zip.c tag_2
and the you apply the patch to that tree. After the patch, you'll be left with:
a/foo.c tag_1 a/y.c (was zip.c) tag_2
with patches made to the contents of both files.
Here's a sample of some subtleties and ways of handling conflicts:
Suppose that the original tree seen by mkpatch has:
Directory or file: Tag:
./a tag_a ./a/b tag_b ./a/b/c tag_c
and that the modified directory has:
./a tag_a ./a/c tag_c ./a/c/b tag_b
Finally, suppose that the tree has:
./x tag_a ./x/b tag_b ./x/c tag_new_directory ./x/c/b tag_diffent_file_named_b ./x/c/q tag_c
When patch gets done with the tree, it will have:
./x tag_a Since the patch doesn't do anything to change the directory with tag_a.
./x/c.orig tag_new_directory ./x/c.rej tag_c Since the patch wants to make the directory with tag_c a subdirectory named "c" of the directory with tag_a, but the tree already had a different directory there, with the tag tag_new_directory.
./x/c.rej/b tag_b Since the patch wants to rename the directory with tag_b to be a subdirectory named "b" of the directory with tag_c.
./x/c.orig/b tag_diffent_file_named_b Since the patch made new changes to this file, it stayed with its parent directory.arch: The arch Revision Control System
regexps.com