Dear Wiki user, You have subscribed to a wiki page or wiki category on "Subversion Wiki" for change notification.
The "SupportedMergeScenarios" page has been changed by JulianFoad: http://wiki.apache.org/subversion/SupportedMergeScenarios?action=diff&rev1=14&rev2=15 Comment: Wording improvements ==== and Why Conflict Resolution is Part of Merging ==== To discuss the nuances of what exactly is tracked in Merge Tracking, we need to think about the difference between a raw change in the repository (a ''commit'') and a concept that we can call a ''logical change''. - Whenever I commit a change that’s not a merge, we can regard that commit as introducing a new ''logical change'' into my project, on a given branch. But when I merge that change to another branch and commit the result, that commit is not creating a new logical change, rather it is creating a new physical representation (in the target branch) of ''the same logical change''. In simple cases the physical change often looks “the same” when viewed as a diff, perhaps with the exception of line numbers and surrounding context lines. In trivial cases, such as a catch-up merge to a target branch that does not yet contain any modifications of its own, the physical change is identical. In general, however, the physical change on the target branch is necessarily different from the source branch change. It is adapted automatically (by Subversion or the user's configured 3-way merge tool) and/or manually (through ''conflict resolution''), to fit the current state of the target branch. ([[#Note_2|2]]) + {{{#!wiki note + This subsection describes a theoretical basis for understanding merging. It does not directly describe the behaviour of Subversion's merge tracking at the moment. + }}} - The distinction between a ''commit'' and a ''logical change'' is important in an automatic merge, when we want to avoid merging any ''logical change'' that is already present on the target branch, no matter from which intermediate branch it arrived there. + Whenever I commit a change that’s not a merge, we can regard that commit as introducing a new ''logical change'' into my project, on a given branch. But when I merge that change to another branch and commit the result, that commit is not creating a new logical change, rather it is creating a new physical representation (in the target branch) of ''the same logical change''. In simple cases the physical change often looks “the same” when viewed as a diff, perhaps with the exception of line numbers and surrounding context lines. In trivial cases, such as a catch-up merge to a target branch that does not yet contain any modifications of its own, the physical change is identical. In general, however, the physical change on the target branch is necessarily different from the source branch change. It is adapted automatically (by Subversion or the user's configured 3-way merge tool) and/or manually (through ''conflict resolution''), to fit the current state of the target branch. ([[#Note_2|2]]) ([[#Note_3|3]]) - The whole subject of merge tracking is about whether to port the a given logical change onto the target branch, or whether that logical change has already been put there. The question is not about the physical representation of that change, since we don't expect the change on the target branch to consist of exactly the same physical edits as it did in the source branch. + The distinction between a ''commit'' and a ''logical change'' is important for merge tracking. The whole purpose of merge tracking is to decide whether to select a given change on the source branch to be merged onto the target branch or whether that logical change has already been put there. The question is about whether ''the same logical change'' is already present on the target branch. The question is not about the physical representation of that change, since we don't expect the change on the target branch to consist of exactly the same physical edits as it did in the source branch. Nor do we care whether whether the change arrived on the target branch by being merged directly from the original revision on the original branch A where that logical change was first committed to the repository, or whether it arrived in the middle of a merge of a batch of changes from branch C, if branch C received the change in a merge from branch B which was merged from branch A. When we want to merge "everything" from branch C to branch A, the merge tracking needs to be able to consider the possible changes to be merged from branch C and realize that the change at revision 130 on branch C is just a merge from branch B which was itself a merge from branch A, and thus we must not try to merge revision 130 of C to A because we already have the logical equivalents of that change in branch A. - {{{#!wiki note - The merge algorithm cannot possibly "know" by inspection whether the physical change that was committed as a merge is a faithful representation the set of ''logical changes'' that the mergeinfo claims it is. As far as ''merge tracking'' is concerned, if the mergeinfo says a given ''logical change'' was merged, it was merged. The user interfaces should assist the user in understanding this. - - The UI may also provide the user with a way to tell Subversion that he/she has merged a given logical change into the WC manually (not using the 'merge' command), or has merged a change into the WC and then decided to remove it before committing and not record it as merged. The command-line interface for these is "svn merge --record-only". - }}} - ### NEW text to be edited in: In order to make sense of this, I consider the definition of a tracked change to be: - * The unit of change tracked is a logical change to the versioned tree, which was originally committed to one branch, which has a meaning or purpose that remains the same no matter which branch it ends up being merged onto. + * The unit of change tracked is a logical change to the versioned tree, which was originally committed to one branch, which has a meaning or purpose that remains the same no matter which branch it ends up being merged onto. The meaning or purpose of a logical change is typically described in the log message of the original commit. A realistic example is "Delete function foo() and change all callers to use the similar function bar() instead". Merge tracking should treat every original commit as that kind of "logical change". This definition doesn't presuppose that every commit is *actually* relevant to every other branch in your project. If and when you want to merge this change to a branch that doesn't have a function foo() and code that calls it, then clearly you have logical conflict between the states of the two branches. This change and almost certainly a series of other changes will either be inapplicable or will need some minor or major editing to resolve the logical conflict to make them applicable. Resolving such conflicts, including omitting changes by hand that the system says logically should be merged, is a normal and expected part of merging. - The physical manifestation of a given logical change will in general differ on different branches. In simple cases the physical manifestation will be similar: for example, the default "svn diff" output may be the same except for the line numbers. In a slightly less trivial example perhaps the context lines will also be different. And getting bit more involved, perhaps the removed "-" lines will be slightly different but the added "+" lines will be just the same. Or perhaps the diff will be just the same except in a renamed file. (Side note: Although what we mean by the physical manifestation is kind of obvious, in fact it is subtly hard to pin down, because it depends entirely how you represent the physical change. If we look at "svn diff" output, for example, differences between the source branch and the target branch in other lines of the file are hidden even though they might be important for the correctness of the patched lines.) + {{{#!wiki note + The merge algorithm cannot possibly "know" by inspection whether the physical change that was committed as a merge is a ''faithful'' representation the set of logical changes that the mergeinfo claims it is. As far as merge tracking is concerned, if the mergeinfo says a given logical change was merged, it was merged. User interfaces should try to assist the user in understanding this. + }}} - It's important to consider complex examples of change. A change like adding "This is a new line" to the end of file "foo" is often too simple to demonstrate merge tracking requirements. With such an example, the tree-merge layer is quite likely to DTRT no matter what the merge tracking layer says. But important changes aren't always like that; important changes often can't be automatically merged at the tree-merge (or text-merge) level. + {{{#!wiki note + The UI may also provide the user with a way to tell Subversion that he/she has merged a given logical change into the WC manually (not using the 'merge' command), or has merged a change into the WC and then decided to remove it before committing and not record it as merged. The command-line interface for these is "svn merge --record-only". + }}} IMPLEMENTATION - Of course the merge tracking implementation is written in terms of tracking physical changes (commits), not logical changes. In simple cases that gives exactly the same result, but I view the ''purpose'' as being to track logical changes, and so when we consider cases where the two approaches require different outcomes then I look at the latter. + The merge tracking implementation is written in terms of tracking physical changes (commits), not logical changes. In simple cases that gives exactly the same result. In particular, it gives the same result when merging from branch A to branch B if we have only ever been merging from branch A to branch B. When we introduce a third branch C, however, and wish that merge tracking would continue to work when we merge from A to B to C to A to C to B to ..., that's when we need to make the distinction. + + Since Subversion 1.5 (through 1.8 at least), the merge tracking stores mergeinfo ''transitively'', so after merging a change from A to B to C, the mergeinfo on branch C will list both the change on branch B that was merged directly to C, and also the change(s) in branch A that were merged directly to branch B and therefore indirectly to branch C. This partly serves to make the merge tracking act as if it is tracking logical changes. A subsequent merge from A to C will not repeat the same changes that are recorded as already merge (indirectly) from A to C, and so in that case it correctly avoids re-merging the logical changes from A that are already on C. But if we try things another way round -- first merge from A to C, and then from A to B to C, the last merge (B to C) will wrongly repeat the changes that already arrived on C in the first merge (directly from A). == Merging Scenarios for Subversion 1.6 == ||||<style="text-align:center;">'''Key''' || @@ -149, +151 @@ Other possible kinds of merging include taking any arbitrary difference between two files or directories -- perhaps on different branches or without any branching history connecting them -- and merge that difference into some other file or directory (perhaps unrelated to either side of that diff). Merge tracking does not try to address such cases, and so we do not consider them here. === Note 2 === - If this change is being merged into a target WC in which other changes have also being merged, and touches some of the same nodes, then similarly this change is also adapted (automatically and/or through manual conflict resolution) to combine with those other changes. + Although what we mean by the physical manifestation of a change is kind of obvious, in fact it is subtly hard to pin down, because it depends entirely how you represent the physical change. + === Note 3 === + Also, if this change is being merged into a target WC in which other changes have also being merged, and touches some of the same nodes, then similarly this change is also adapted (automatically and/or through manual conflict resolution) to combine with those other changes. +
