SvnHelp >
Moving patches around: merging and backporting
Merging vs. Using patches
When you need to move a patch from a directory to another (so moving across branches, trunk or whatever), the correct thing to do is to invoke svn merge svn merge analyzes a set of revisions, extracts the differences and applies them to the specified working copy, as local modifications. The differences can then be reviewed as usual svn status svn diff and committed svn commit .
So, why couldn't this be done using svn diff + (GNU) patch There are at least two very good reasons.
- A textual patch doesn't say it all! While most of a change can be expressed in a patch file, there are more things that can be done in a SVN repositories which cannot be correctly expressed in a patch.
If you add/delete a file, GNU patch knows how to create/delete it in the filesystem, but it does not know anything about the SVN repository. svn merge is smarter and will add/remove it to the source control for you.
If you copy/rename/move a file, the patch will simply show the old file as gone, and the new file as appeared. svn merge will import the correct operation, which will preserve the history of the file. Thus, you can even rename and modify a file in a single commit: svn merge will import it correctly.
Any kind of operation on the properties (so-called SVN metadata attached to files/directories) can't be expressed as textual patches in a format that GNU patch will understand. Instead, svn merge will import also metadata changes correctly.
svn diff does not know anything about the ancestry of a file. Let's say you have a set of commits that remove a file called foo.c and then copy a file with similar contents bar.c over foo.c If you diff across these changes, you'll see only a patch containing the text differences. But applying this patch would be incorrect, because the new foo.c is a copy of bar.c (if you svn log foo.c you want to see the copy and then go through the history of bar.c . svn merge studies the history of the files, and realizes what exactly needs to be done to merge the changes (so it'll delete the old file, and do the copy).
Backporting a patch
Let's say you have just done a commit in the trunk. The revision number of this change is r62450 (if you did not take note of this, you can use svn log to find it out, or look into the gcc-cvs mailing list archives). You want to backport it to a release branch, say GCC 4.0. The first thing to do is getting a working copy of the GCC 4.0 branch. If you have one already around, fine. Otherwise you can switch your trunk working copy:
$ svn info | grep URL URL: svn+ssh://gcc.gnu.org/svn/gcc/trunk $ svn switch svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_0-branch U gcc/reload.c U gcc/expr.c [...] Updated to revision 62453. $ svn info | grep URL URL: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_0-branch
Advisory Note: If you experience SSH connection problems, you may need to include your username in the path to svn. (e.g. svn+ssh://myusername@gcc.gnu.org/svn/gcc/trunk)
Switching a working copy is much much faster than checking out the whole branch: it only downloads and applies the differences svn switch is just a smart version of svn update . svn switch will also keep any local modifications you have in your tree and try to reapply them against the new branch (but obviously if they don't apply correctly you'll have to resolve the conflicts).
Now, it's time for merging the change. This is as simple as:
$ svn merge -r62449:62450 svn+ssh://gcc.gnu.org/svn/gcc/trunk G gcc/cp/parser.c A gcc/cp/reflection.c G gcc/cp/Make-lang.in
This merge modified two files parser.c and Make-lang.in and added a new file reflection.c . Now, if you check for the status, it should reflect exactly what the merge did:
$ svn status G gcc/cp/parser.c A gcc/cp/reflection.c G gcc/cp/Make-lang.in
You can further review the changes with svn diff solve any conflict that might happen (and remember to use svn resolved after that!) and finally commit the patch (with svn commit . Remember to test it though!
Alternative: use svnmerge
It seems that the svnmerge utility (also known as svnmerge.py) is a simpler way to do that. See SvnBranch.