Resolving Conflicts in UM FCM
Before proceeding ensure you have completed the Setting Up , Running UM FCM jobs and Making Code Changes sections of the tutorial.
Introduction and Merging
Introduction
This tutorial is designed to give you a little experience with the various ways you can use xxdiff (the FCM merge tool) to resolve conflicts as the result of a merge. It can, of course, only provide a limited set of examples, but these should be representative of what can be achieved.
Merging
In the code changes tutorial you had an introduction to merges and conflicts. It might be worth reviewing this before you go any further.
For the purposes of this tutorial, 2 branches have been set-up so you can merge one into the other and resolve the conflicts that result. They are fcm:um_tutorial_br/dev/ros/VN7.1_branch_one and fcm:um_tutorial_br/dev/ros/VN7.1_branch_two.
We wish to take VN7.1_branch_one as our base code and merge VN7.1_branch_two into it. To do this, you can either checkout VN7.1_branch_one by typing
fcm checkout fcm:um_tutorial_br/dev/ros/VN7.1_branch_one
or, if you have a pre-existing UM tutorial working copy you can cd into this and type
fcm switch fcm:um_tutorial_br/dev/ros/VN7.1_branch_one
to switch the working copy to the branch. Your working copy should now contain a copy of the VN7.1_branch_one branch. You can confirm this by changing directory to the top level of your working copy and typing
fcm info
to which you should get something similar to the following
ros@puma$ fcm info => svn info Path: . URL: svn://puma/UM_TUTORIAL_svn/UM/branches/dev/ros/VN7.1_branch_one Repository Root: svn://puma/UM_TUTORIAL_svn Repository UUID: 128fe4f4-ca53-0410-8b5d-f5eaa65b2c12 Revision: 1229 Node Kind: directory Schedule: normal Last Changed Author: ros Last Changed Rev: 1229 Last Changed Date: 2009-04-28 09:28:45 +0100 (Tue, 28 Apr 2009)
Note the URL points to the VN7.1_branch_one.
Now we can perform the merge. To do this, check you are in the top-level directory of the working copy and then type
fcm merge fcm:um_tutorial_br/dev/ros/VN7.1_branch_two
and you should be greeted by the following,
Available Merges From /UM/branches/dev/ros/VN7.1_branch_two: 1231 1230 Please enter the revision you wish to merge from (or just press <return> for "1231"):
You will note that you are offered the option of choosing the revision of the branch that you wish to merge into your working copy. The version we want for this tutorial is the most recent (1231), so just press return. This gives the following message,
About to merge in changes from /UM/branches/dev/ros/VN7.1_branch_two@1231 compared with /UM/trunk@1198 This merge will result in the following changes: -------------------------------------------------------------------------------- C src/control/top_level/veg_ctl.F90 C src/control/mpp/file_open.F90 C src/atmosphere/land_surface/pdm.F90 -------------------------------------------------------------------------------- Would you like to go ahead with the merge? Enter "y" or "n" (or just press <return> for "n"):
This tells you that the 3 named files will be updated, and that all 3 of them will result in conflicts (the C in the first column indicates this). You are asked if you wish to continue with the merge and pressing n will result in aborting the merge and leaving your working copy untouched. In this case however, we do wish to continue, so type y. For each file in conflict you are then given several options, for the purposes of this tutorial enter p to postpone. This then gives the following message,
Performing merge ... Conflict discovered in 'src/control/top_level/veg_ctl.F90'. Select: (p) postpone, (df) diff-full, (e) edit, (h) help for more options: p --- Merging r1199 through r1231 into '.': C src/control/top_level/veg_ctl.F90 Conflict discovered in 'src/control/mpp/file_open.F90'. Select: (p) postpone, (df) diff-full, (e) edit, (h) help for more options: p C src/control/mpp/file_open.F90 Conflict discovered in 'src/atmosphere/land_surface/pdm.F90'. Select: (p) postpone, (df) diff-full, (e) edit, (h) help for more options: p C src/atmosphere/land_surface/pdm.F90
Using the command
fcm status
at this point will give the following information
ros@puma$ fcm status => svn status ? src/control/top_level/veg_ctl.F90.merge-left.r1198 ? src/control/top_level/veg_ctl.F90.working ? src/control/top_level/veg_ctl.F90.merge-right.r1231 C src/control/top_level/veg_ctl.F90 ? src/control/mpp/file_open.F90.working ? src/control/mpp/file_open.F90.merge-right.r1231 ? src/control/mpp/file_open.F90.merge-left.r1198 C src/control/mpp/file_open.F90 ? src/atmosphere/land_surface/pdm.F90.merge-left.r1198 ? src/atmosphere/land_surface/pdm.F90.working ? src/atmosphere/land_surface/pdm.F90.merge-right.r1231 C src/atmosphere/land_surface/pdm.F90
This tells us that the 3 files have been updated and are in conflict, and that FCM has introduced a number of temporary files (3 for each file in conflict) that will be needed by the system when we resolve the conflicts - we don't need to know what is in the files at this stage.
At this point we have completed the merge, but our working copy isn't usable due to the conflicts so the next stage is to resolve these. Remember throughout this process that merges and conflict resolution are performed in a working copy so if you stuff things up really badly you can either use
fcm revert -R .
to go back to a pristine working copy or just delete the working copy and start again!
Conflict Resolution Introduction
The FCM command for resolving conflicts is fcm conflicts. If you specify it without any arguments, it will run through all the files that are in conflict consecutively. Alternatively, if you wish to choose the order of the files you wish to resolve conflicts in, you can use fcm conflicts <filename> to specify the file. Normally the first approach is used as the order doesn't matter, but this tutorial will use the second approach to ensure the tasks are in the right order!
The tool used for resolving conflicts is xxdiff. This is the same tool that is used by FCM for showing differences, but when used for resolving conflicts it has different menu choices and a different appearance. This section of the tutorial will explain what the different panels mean so we can do exercises with it later.
The following screengrab is typical of the sort of display that xxdiff will provide
Number of Unresolved Conflicts. The figure in the top-right corner (circled in dashed blue for this example only) indicates the number of unresolved conflicts remaining. When resolving conflicts the aim is to get this number down to 0.
Left Panel. The left panel contains the working copy from before the merge. Thus in our example it will contain the code in VN7.1_branch_one.
Right Panel. The right panel contains the code that is being merged in. So, in our examples it will contain the code in VN7.1_branch_two.
Middle Panel. The middle panel contains the so called common ancestor. Inthe common case that both branches are from the same point of the trunk, this will be the trunk at the point the branch was made. In other words, the middle panel shows the code before anyonestarted making changes. This can be useful as it shows where both changes started from and can help in working out exactly what was done by each change.
Green Highlight. Lines highlighted in green are unselected. This isthe default colour - it can be customised in your $HOME/.xxdiffrc file.
Purple Highlight. Lines highlighted in purple are selected. Again a default that can be customised.
Hatched Background. Lines that have a hatched background don't really exist. They are there as a 'blank alternative' to the lines in the other panels.
Navigation. You are probably aware from using xxdiff as a differencing tool that you can use keyboard shortcuts to navigate the file. This is also true when resolving conflicts,
- n Next Difference (also View -> Next difference)
- p Previous Difference (also View -> Previous difference)
- b Next Unresolved Conflict (also View-> Next unresolved)
- o Previous Unresolved Conflict (also View-> Previous unresolved)
The latter two options are the most useful when resolving conflicts.
Merged view. The menu item Windows -> Toggle popup merged view will give you a new window that shows the result of the merge that updates interactively as you make selections. Alternatively Windows -> Toggle pane merged view will add a new panel at the top that interactively shows the merged code.
The Aim. The aim of resolving conflicts is to ensure one block (from the left, right or middle panels) is selected for each difference. xxdiff will have done all the obvious ones for you (i.e. where changes are not on the same lines) and the only ones left to do are the awkward ones! Note that you can select a block by using the left mouse button.
Using Split/Swap/Join?
OK - so much for the theory! Now it is time to try some real conflict resolution. The first example is where two changes have been made in the same place and we want to keep all of both changes, but making sure we get them in the right order. To get going, type
fcm conflicts src/control/mpp/file_open.F90
and you should get a xxdiff window. Type b to get to the first unresolved conflict and you should see the following:
We can see that there is just one unresolved conflict in this file and it is where we have 2 history comments added. We wish to keep both of these and ensure that the vn6.6 comment comes before the vn7.1 comment.
This is where the 'Split/Swap/Join?' command comes in. It can be found either under the menu Region -> Split/Swap/Join? or by using the s key shortcut. Using this option will split the current region into two. Using the command again will swap the order of the two regions, and using it a third time will go back to the original single region. For more complicated changes, the split may be into more regions and subsequent uses of the command will cycle through all possible orderings before finally re-joining them into the original region.
To get the result we neeed this time, use Split/Swap/Join? twice to get the change comment in the right-hand panel first and the change comment in the left-hand panel second. Then use the left mouse button to select both the change comments. You should notice that the remaining conflicts number in the top-right corner has become 0. If you've done this correctly, you should have the following situation:
Once you are sure you've got the correct resolution of the conflict (you may wish to use the Merged View to check), we can exit xxdiff by using the File -> Exit with MERGED command (or m keyboard shortcut). This tells FCM that the merge has been successful. If you have made a mistake and want to abandon your attempt at conflict resolution,you can use File -> Exit with REJECT (or r shortcut).
Once you've resolved the conflicts FCM will give you the following text
You merged all the changes. Would you like to run "svn resolved"? Enter "y" or "n" (or just press <return> for "n"): y
Enter y if you are convinced you've resolved the conflict correctly and you should be given the following message:
Resolved conflicted state of 'file_open.F90'
Congratulations - you have resolved your first awkward conflict!
Using middle-mouse button line selection
Having learned a technique for using xxdiff for conflict resolution we can use this in conjunction with a new technique for more difficult conflicts. In your working copy, type:
fcm conflicts src/control/top_level/veg_ctl.F90
and then in xxdiff type b to go to the first uresolved conflict. You should see the following situation:
Firstly, I apologise for the variable names and syntax errors!
You can see that in VN7.1_branch_one(i.e. the left panel) 3 new arguments were added to the argument list, new_argument1, new, newer after the DIM_CS1, DIM_CS2 arguments. In the other branch, VN7.1_branch_two (i.e. the right panel) 3 other arguments have been added. In this case, wibble, wobble were added before the global_row_length, global_rows arguments and arg_2 added after these.
It is clear that we want our final argument list to be (with appropriate continuations)
wibble, wobble, global_row_length, global_rows, arg_2 DIM_CS1, DIM_CS2,new_argument1 new,newer
This is actually a fairly difficult conflict to resolve and you might find the Merged view rather handy in making sure you've got the right solution!
To start with we need to have some options of which code to choose. Split/Swap/Join? is again the tool of choice for this. In this case Split/Swap/Join? will split the conflict into 3 sections and thus there are 6 potential orders that the sections could have. In this case we need to make sure that the blocks are ordered correctly for the newly introduced variables to be in the correct order. Using Split/Swap/Join? a total of 5 times (you might appreciate the shortcut s at this point!) should give you the following:
Now we have the blocks in the right order, we need to select the code we need. Unfortunately, some code is repeated in each of the blocks, so choosing code at a block level isn't enough. The middle mouse button however can be used to select individual lines. Thus to get the correct code in this case we need to
- Use the middle mouse button to select the wibble, wobble line from the right panel,
- Use the middle mouse button to select the global_row_length, global_rows, arg_2 line from the right panel,
- Use the middle mouse button to select the DIM_CS1, DIM_CS2, new_argument1 line from the left panel,
- Use the middle mouse button to select the new, newer line from the left panel
At this point, we have chosen all the code we need, but the Conflict Remaining indicator in the top-right corner of xxdiff shows we have 3 conflicts remaining. These are the lines still coloured green. To get rid of these use the middle mouse button to click on hte panel that has hatched backgrounds (rather than code). This ensures that nothing (not even a blank line) is selected rather than code for these lines. The next screenshot shows the hatched lines you need to click on in a light red. The red will not be in your xxdiff window - this is just for illustrative purposes.
When you've done the selections correctly, you should have the following:
Once you've done this, you can use File -> Exit with MERGED (or shortcut m) and answer y to the request to run svn resolved as you did for the previous case. Once this is complete, you'll have resolved the second conflict!
Editing a file to resolve conflict
We've seen that a few clicks can resolve some fairly awkward conflicts, but there are some situations that it is impossible to resolve in such a way and for which you'll need to edit one of the files involved. You can do this from within xxdiff and this section will show you how.
Before we start, however, we need to make sure xxdiff is set up to use the editor of your choice. By default, xxdiff will use the editor that is specified in your $EDITOR environment variable. Note that this needs to be an editor that will display in its own window (so gvim -f is OK, but vi isn't). If $EDITOR specifies the editor you wish to use, all is OK. If not, you can either set this variable (e.g. by typing export EDITOR=nedit) or you can set the variable in the xxdiff options file. To do the latter, you will need to create (or edit if it already exists) the $HOME/.xxdiffrc file and add a line to specify the editor. Examples might be:
- Command.Edit: "nedit"
- Command.Edit: "gvim -f"
- Command.Edit: "emacs"
The final conflict to resolve can be set up by typing
fcm conflicts src/atmosphere/land_surface/pdm.F90
in your working copy. Using b to go to the unresolved conflict, you will see the following:
Note the VN7.1_branch_one has added the argument NEW_1 to a line and that VN7.1_branch_two has added the argument NEW_2 to the same line. Clearly to resolve the clash we need both arguments included in a particular order (we'll assume NEW_1 comes before NEW_2 in this case!). This conflict can't be split as it is on a single lines so none of the tools we've used previously will help. The only way to resolve it is to edit one of the files. xxdiff provides the ability to launch an editor on one of the files. The best file to choose is the one that will require fewest changes - in this case it doesn't matter, so we'll edit the left one arbitarily.
The File -> Edit left file menu will launch an editor with a copy of the left file in it (remember this corresponds to the working copy - hence VN7.1_branch_one in this case). Edit the line with the new argument on it to add NEW_2,. The line should now read:
& NPNTS,SOIL_PTS,SOIL_INDEX,NSHYD,NEW_1,NEW_2, &
Then save and exit your editor in the normal way.
You'll not see any difference in xxdiff at this stage as it is still working with the previous version of the file. Using File -> Redo diff will re-compute the difference map and you will see that the edited version of the file is being used.
Unfortunately, redoing diffs will get rid of any automatically resolved conflicts, so the Unresolved Conflict indicator in the top-right corner will be 3. You now need to re-do the automatic conflict resolution by using the Global -> Merge menu item. After doing this, only 1 unresolved conflict will be left, which is the line we had previously edited. Clicking the region in the left panel will choose our edited version to complete resolving the conflicts.
Remember to File -> Exit with MERGED and to answer y to run svn resolved
At this stage you should have resolved all the conflicts and
fcm status
should give you
=> svn status M src/control/top_level/veg_ctl.F90 M src/control/mpp/file_open.F90 M src/atmosphere/land_surface/pdm/F90
which shows no files in conflict. At this stage you would usually think about committing your change to the branch, but please don't do it for this example.
Useful Links
- FCM User Guide on Resolving Conflicts
- xxdiff manual, "Merging files and resolving conflicts"
- xxdiff manual
For queries / corrections / suggestions email: r.s.hatcher(at)reading.ac.uk