Tuesday, January 6, 2009

[CVS] How to overwrite all files in HEAD/TRUNK with all files from a BRANCH.

If you are using CVS and have a branch that contains whatever code is in production, and you use HEAD/TRUNK for future development, you can sometimes end up in situations where you really want to overwrite whatever is in HEAD/TRUNK with the latest production version from your BRANCH.

In this and many other cases the following might come in hand...

The bottom line is that you need to execute the following four cvs commands:
Reset sticky tag:
   cvs up -A <Filename>
Update from branch:
   cvs update -r<YourBranchName> -p <Filename> > <Filename>
Add uncommitted files:
   cvs add <UnCommmittedFilenames>
Commit changes:
   cvs commit

In case that wasn't enough for you, here's a little more info that I hope will be understandable... Otherwise, just ask!

- Run UNIX bash shell... :)
- filenames and pathnames can contain spaces (as the bash "for" will split the filename into separate files).
- Two directories exist, one with the development HEAD/TRUNK version called "/home/me/myproject_head" and one with the production BRANCH called "/home/me/myproject_branch".
- No new directories have been added/removed. If you have added or removed any directories you need to modify the bash commands below with something like "mkdir -p $i" (also remove the filename from $i) for creating the directories that doesn't exist.

Start out by removing all the files you have in your HEAD/TRUNK directory
for i in `find /home/me/myproject_head -type f \
   | grep -v CVS`; do rm $i;\

In the above case, I've added a grep -v for "CVS" as all files/directories containing this name should be excluded from the deletion, since we need these files if we later on want to commit (and we do!).

Now copy all files that you want to replace from the BRANCH directory to the HEAD directory.
Start out by running a "cd /home/me/myproject_branch".
for i in `find . -type f \ 
   | grep -v CVS | grep -v "org.eclipse" \
   | cut -b 3-`; do \
   cp /home/me/myproject_branch/$i `echo "/home/me/myproject_head/$i"`; \

In this case i have chosen not to copy the CVS directories (a MUST), however I've also chosen to exclude the org.eclipse from the copy, as I have directories that are eclipse specific that I don't want to copy. You can add more " | grep -v partialname" if you wish.

So, now we can work on the new files with the old cvs structure.

First we need to make sure no sticky tags exist:
for i in `find /home/me/myproject_head/ -type f \
   | grep -v CVS | grep -v "org.eclipse"`; do \
   cvs up -A $i; \

Then we replace the files in HEAD/TRUNK with the ones from the BRANCH in cvs:
for i in `find /home/me/myproject_head/ -type f \
   | grep -v CVS | grep -v "org.eclipse"`; do \
   cvs update -rMY_PROJECT_BRANCH_XX -p $i > $i; \

This states that we want to take all the files in our local HEAD/TRUNK version and overwrite them with the versions that exist in the "MY_PROJECT_BRANCH_XX" branch in cvs.

Finally, before we call commit we need to add all the files that exists in the BRANCH but haven't yet been added to HEAD/TRUNK. This requires that you execute "cd /home/me/myproject_head/"
for i in `cvs -nq up | grep "? " | cut -d " " -f2 `; do\
   cvs add $i; \

Now we are ready to commit:

That's it... You should now have a working HEAD containing the same as the stuff in your BRANCH!

The example above can probably be simplified, however this is how I did... Feel free to comment if you have a more simple solution!



Unknown said...

Hi Jakob, I was looking to do this very thing and came across your post. Thanks.

I also found the following article http://kb.wisc.edu/middleware/page.php?id=4087#replacing

Here the final scenario may describe a simpler way - though I yet to "commit" to either. (Sorry about the pun.)


Jakob Maaløe said...

Cool, thanks for the comment! :)

- Jakob