2. MergeA version control system like Subversion allows the members of a group project to work on different branches of the project. The good news is that they can work on the project at the same time without interfering with each other, but the downside is that the changes made by each member are not automatically shared by others. This is where the merge operation comes in, which, in a sense, copies changes between different branches of a project. In this section, we first explain the semantics of the merge operation in Subversion, then discuss several merge scenarios that are common in a group project setting. 2.1 The Semantics of Merge in SubversionThe merge operation in Subversion take two parameters, a Source URL (a.k.a From URL or Start URL), and a Target URL (a.k.a. To URL or End URL):
The semantics of the merge operation is the following: Compare the version of the project represented by the source URL and the version represented by the Target URL, calculate the changes needed to transform the source version to the target version, and apply these changes to the working copy. There are several things worth noting here. First of all, when people look at terms like Source URL and Target URL, they tend to think that the changes come from the source version and will be copied to the target version. However, in Subversion it is actually the opposite - the target version has the changes the source version wants. The terms source and target (or from and to) refer to the states of the project before and after the changes are applied, not the source and the target of the changes themselves. Secondly, note that the changes (i.e. differences) bwteeen the source and the target version are applied to the working copy, not the branch in the repository. In other words, nothing changes in the repository after a merge until you perform a commit operation. Thirdly, a URL in Subversion is the combination of a repository location and a revision number. When the revision number is not specified, by default it is assumed to be the latest revision at the repository location, which is known as the HEAD revision. Sometimes you might want to extract the changes between two revisions at the same repository locations, and in those case you must specify the revision number explicitly, for example:
In this example Subversion would extract the changes between Revision 3 and Revision 2 at the repository location svn://cs3/hello/branches/StudentA-branch and apply these changes to the working copy. 2.2. Preparation Before MergeMerge can be a little tricky, and to make the process as smooth as possible, a little preparation before merge is recommended. First, commit all local changes and make sure the working copy is up to date. Specifically, if the working copy has local changes, perform a commit operation; if the working copy has no local changes, perform an update operation.
Second, take a look at the changes to be merged before doing the merge. For example, suppose Student A made some changes to the
Figure 2.2.1 Revision History of Student A's Branch
The revision history shows the list revisions at the repository location /branches/StudentA-branch. Selecting a revision in the list will reveal further details about the revision. For example, when Revision 5 is A screen capture video illustrating this process is available here. 2.3 Common Merge ScenariosWe now discuss three common merge scenarios. In all three cases we assume that both Student A and B start with the same version of the project in their branches. 2.3.1 Changes on One SideSuppose Student A made some changes to HelloWorld.java and committed them to the repository, and Student B wants to copy these changes to his or her branch. We call this scenario Changes on One Side. In Eclipse, Student B can right click on the project and select Team -> Merge. The Merge screen will pop up asking Student B to enter the source and the target URL for the merge. Note that in this case, Student B has not made any changes, so to extract the changes made by Student A, we can simply take the differences between StudentA-branch and StduentB-branch, as shown in Table 2.3.1.1.
Table 2.3.1.1 Source and Target URLs for Merge Scenario #1 After the merge, the changes made by Student A will be applied to the working copy of Student B, as shown in Figure 2.3.1.1. Student B can then commit the changes to his or her branch.
Figure 2.3.1.1 Merge Scenario #1 - After Merge A screen capture video illustrating this process is available here. 2.3.2 Non-conflicting Changes on Both SidesSuppose Student A added a new class Foo, while Student B added a new class Bar, as shown in Figure 2.3.2.1. Note that these two classes are in different files under differnt folders, so they do not conflict with each other. We call this scenario Non-conflicting Changes on Both Sides.
Figure 2.3.2.1 Merge Scenario #2 - Before Merge Let's first consider how Student B can copy the changes made by Student A. If we use the same source and target URL as in the first scenario, we would notice that changes made by Student B (i.e. the Bar class) will be removed, and this is certainly not what we want. We note that unlike the first scenario, in this case we do not want to transform StudentB-branch into StudentA-branch; instead, we simply want to copy over the changes made by Student A, so the question becomes how do we extract these changes? Based on the semantics of merge, the answer is quite simple: they are simply the differences between the two revisions of StudentA-branch before and after the changes.
Table 2.3.2.1 Source and Target URLs for Merge Scenario #2 Table 2.3.2.1 shows the source and target URLs that should be used in this scenario, and the results of the merge is shown in Figure 2.3.2.2.
Figure 2.3.2.2 Merge Scenario #2 - After Merge To copy Student B's changes, Student A can perform a similar merge operation with the source and target URLs being two revisions of StudentB-branch. A screen capture video illustrating this process is available here. 2.3.3 Conflicting Changes on Both SidesSuppose both Student A and Student B made changes to HelloWorld.java, and we call this scenario Conflicting Changes on Both Sides. To copy changes from Student A, Student B can perform a merge operation with the same source and target URLs as shown in Table 2.3.2.1. However, because both students have modified HelloWorld.java, this merge operation will lead to a conflict, as shown in Figure 2.3.3.1.
Figure 2.3.3.1 Merge Conflict Note that when a conflict happens, Subversion will do several things:
To resolve the conflict, Student B can manually edit HelloWorld.java, then right click on the file name and select Team -> Mark Resolved.
Figure 2.3.3.2 Mark Resolved Screen The Mark Resolved screen is shown in Figure 2.3.3.2. Since Student B manually edited the source file to resolve the conflict, the first option is selected. Note that instead of manually editing the source file, one can also resolve a conflict at this screen by simply choosing which version of the file to keep. After the conflict is resolved, Student B can commit the changes as usual. A screen capture video illustrating this process is available here. 2.4 SummaryMerge simply extracts the differences between two revisions represented by the source and the target URL, and apply these differences to a working copy. The key of a merge is to identify the proper source and target URLs.
The complexity of merge comes from the conflicts. To avoid excessive conflicts, merge should be done regularly between two actively developed branches, i.e. do not wait until they grow too far apart. |