Showing posts with label Subversion. Show all posts
Showing posts with label Subversion. Show all posts

Tuesday, November 26, 2013

How to downgrade SVN in Arch Linux

Whenever I do an update to arch, it installs a new version of subversion, which is as it should be. At the moment, the latest is SVN 1.8.3. However, several of the development tools I use depend on svnkit, which currently supports SVN 1.7.x. So to keep my command line svn compatible with my svnkit-based tools, I need to downgrade. As usual, I'm adding this blog entry so I can remember how to do this. It's pretty simple:

  1. cd /var/cache/pacman/pkg
  2. ls sub*
    subversion-1.7.9-4-x86_64.pkg.tar.xz  subversion-1.8.0-1-x86_64.pkg.tar.xz
    subversion-1.7.9-6-x86_64.pkg.tar.xz  subversion-1.8.3-1-x86_64.pkg.tar.xz
  3. sudo pacman -U subversion-1.7.9-6-x86_64.pkg.tar.xz
That is all. Or maybe not. Might need this:

cd /usr/lib
sudo ln -s libserf-1.so.3.0.0 libserf-1.so.0

svn --version will either work or say it's missing libserf.

Last resort: This happened recently, I updated arch and got SVN 1.9.5. My svnkit is still 1.8.12. I tried following the above, but since I'd also upgraded my hard drive recently, I didn't have any old packages in /var/cache/pacman/pkg. I couldn't find the older tar.xz files for SVN 1.8 anywhere (maybe they are out there, I just couldn't find them). So in my .bashrc file, I added these lines:

export PATH=$PATH:/home/danson/src/svnkit-1.8.12/bin
alias svn="jsvn"

This means I'm now using the svn client from svnkit instead of the official svn client from Apache. If I really need the Apache client, it's still there in /usr/bin, so I'm covered either way.


Monday, December 10, 2012

Fixing a tree conflict in svn

This comes up often enough to be a problem, but not so often that I remember the fix.

The situation: The team is working on a development branch, is doing daily merges from trunk to the branch, and is making bug fixes on trunk. New files are added to trunk, and also added to the branch. This add on the branch was done manually, rather than adding just to trunk and then merging.

The problem: To do the daily merge from trunk, I change into a local directory that has the branch code then run

svn merge --dry-run http://server/path/trunk

The usual svn output shows a few conflicts:

danson$ svn merge --dry-run http://server.path/trunk
--- Merging r2733 through r2767 into '.':
C    path/file1.xml
C    path/file2.xml
C    path/file3.xml
C    path/file4.xml
   C path/dir1
C    path/file5.xml
U    path/file6.jsp
U    path/file7.jsp
A    path/file8.jsp

... snip ...
Summary of conflicts:
  Text conflicts: 5
  Tree conflicts: 1


It's that 5th line that is the tree conflict. Cleaning up the other conflicts, then running svn status still shows this:

A  +    path/dir1
A  +    path/dir1/file1.jsp
A  +    path/dir1/file2.xml
A  +    path/dir1/file3.xml
A  +    path/dir1/file4.xml
      C path/dir1
      >   local add, incoming add upon merge


It's possible to get other messages here, depending on what has happened. For example, if a file or directory has been deleted in the branch, but still exists in trunk, you would see:

local delete, incoming edit upon merge

The solution: Since these are new files and the files are identical in both the branch and in trunk, all that needs to happen is to tell svn that one or the other are acceptable. I'll use the branch version since I'm already in that directory:

danson$ svn resolve --accept working path/dir1
Resolved conflicted state of 'path/dir1'

That's it. Build, test, and commit as usual. In the case where the files are actually different, you might want to use something other than 'working' as the argument to --accept. The full list of arguments is here.

Tuesday, October 7, 2008

How to branch and merge with Subversion

These are my rules, your mileage may vary.

In the svn world, branches and tags are essentially the same thing. They are copies of code. By convention, trunk is for work for the next release, branches are for subsequent releases, and a tag is a snapshot of trunk or a branch.

Branching rules:
1. Branch late. Merging is hard, the longer you can put off making a branch, the easier it will be to merge it later on.
2. Branch only when necessary. It is necessary when the check in policy on a code line changes, for example, trunk is locked down as a release is pending and you have code for the next release.
3. Branch remotely. Create branches directly in the repository, not from your local working copies. The check in comment for a branch should state why the branch was created.
4. Branch from trunk. Avoid branching from a branch. Sometimes it is necessary, but avoid if at all possible. It just makes merging harder.
5. Keep a branch and merge map. Use a drawing or notes to keep track, check this document into subversion in the base of your project and keep it up to date.

Tagging rules:
1. Tag often. The check in comment for a tag should state why the tag was created.
2. Tag remotely. Create tags directly in the repository, not from your local working copies.
3. Tag releases. Make sure you can tell release tags from other tags.
4. Mark release tags on your branch and merge map.
5. Tags should be treated as immutable. Don't check in changes in a tag, make a new tag instead.

Merging rules:
1. Merge often. It is easier to do a number of small merges, like on a weekly basis, rather than a single large merge after months of changes.
2. Merge locally. Do clean check outs of the code to be merged, do the merge, build and run unit tests until you are convinced the merge is correct. Commit only when satisfied.
3. Mark merges on your branch and merge map.
4. Don't overlap merges. If you already merged from revisions 100 through 120, the next merge should not be 100 through 140, it should be 121 through 140. (Update: SVN 1.5 now handles this situation automatically, but you need both a 1.5 client and server.)

The Switching rule:
The svn "switch" command makes it easy to change your working copy from code in one branch to code in another. The rule for switching is that there must not be local modifications that have not yet been committed. Check status on your local working copy before switching to a new branch. Commit or revert any changes before switching, otherwise, locally modified files will not be part of the switch and you may inadvertently check in code on the wrong branch.


Branch command:

svn copy http://svn.example.com/repos/calc/trunk \
http://svn.example.com/repos/calc/branches/my-calc-branch \
-m "Creating a private branch of /calc/trunk."

Subversion will automatically commit with this command.


Tag command:

svn copy http://svn.example.com/repos/calc/trunk \
http://svn.example.com/repos/calc/tags/release-1.0 \
-m "Tagging the 1.0 release of the 'calc' project."

Notice this is identical to the branch command. Again, Subversion will automatically commit with this command. By convention, tags should be treated as immutable. This is not enforced by Subversion.


Switch command:
Switching is a two step process:

1. Check status of your local working copies:

svn status

Ensure there are no locally modified files. If there are, either commit or revert your changes before switching.

2. Do the switch:

svn switch http://svn.example.com/repos/calc/branches/newbranch


Merge command:

Merging is a several step process. In this example, the merge will be from trunk to a branch.
1. Create a new, empty directory in which to do the merge:

mkdir merge
cd merge

2. In this directory, check out both the source and destination branches. This gives you two directories, "branch" and "trunk":

svn co http://svn.example.com/repos/calc/trunk ./trunk
svn co http://svn.example.com/repos/calc/branches/my-calc-branch ./branch

3. cd into the top of the destination directory:

cd branch

4. From your branch and merge map, determine what revisions to merge. For example, your branch was created at revision 100 and you want to merge the latest code from trunk to your branch, so your revisions are 100:HEAD. If in doubt, do a log on the branch:

svn log --recursive -v .

The last line of the log output will tell you what revision the branch was created from. Read the log entries for notes about previous merges.

5. Do a dry run:

svn merge --dry-run -r 100:HEAD ../trunk .

This means merge the code in ../trunk into the current directory (which is 'branch') and put the results in the current directory. Start the merge at revision 100 and merge all changes through HEAD. --dry-run means don't really do the merge, just show the output of what would happen.

If you see a lot of "Skipping" messages, it means you are probably merging backwards. Order is important in the merge command, this command:

svn merge --dry-run -r 100:HEAD . ../trunk

does not do the same as the command above. The merge command could be read like this:

svn merge from_this_code to_this_code

The results will be put in the current directory.


6. Do the merge:

svn merge -r 100:HEAD ../trunk .

7, Resolve conflicts. This is usually the hard part, and may require assistance from the authors of the conflicting code.

8. Build and run unit tests.

9. Commit. Make a note of the revision number on your branch and merge map. Next week when you want to merge from trunk again, use this revision number as your starting revision.