How Subversion Merges a File

This page is an attempt to formalize how Subversion merges changes to a single file. It aims to cover all the user-visible aspects, including details such as:

File Merge - General Definition

A 3-way diff style of merge is used, for both props and text. (That is, the fact that 'left' might not be the youngest common ancestor is not taken into account: the "4-way diff" aka "variance-adjusted patching" technique is not used.)

Properties and Text

Props are merged independently of the text, whereas the text merge can be affected by some of the properties, notably svn:keywords and svn:eol-style. The on-disk 'executable' and 'read-only' attributes also may be altered, depending on the properties and on whether a lock is known to be held on this node's repository path.

Properties Merge

For each property name 'P', a merge is performed on the three values (of property 'P' from each of the three node-versions), independently of any other property name. Where one or two of the three node-versions do not have the property named 'P', the value is regarded as 'null'.

svn:mergeinfo is merged semantically. ### All other properties are merged without semantic interpretation of the values?

If the values conflict, a 'property conflict' is recorded for the property name 'P'. Property conflicts may be recorded for none, any or all of the property names involved in the merge. ### See 'Conflicts'.

Text Translation

The following table show what translations are performed between "repository normal form" (RNF) and "working copy form" (WCF):

svn:special

yes

no

no

no

no

svn:mime-type

n/a [1]

bin

txt

txt

txt

svn:eol-style

n/a

n/a

no

'native'

'CR', 'CRLF', 'LF' ###?

What's translated?

symlink

kw

kw

kw, eol

kw (and eol is repaired if another type is encountered)

On-disk attributes?

none [2]

ro, x

ro, x

ro, x

ro, x

To prepare for a merge:

Translating 'mine'

The 'mine' text is translated as follows (in principle), to end up in RNF for comparison with the incoming 'left' and 'right' texts:

  1. translate to RNF, according to the old 'mine' props
  2. translate to WCF and back to RNF, according to the new merged props [4]

Step 1 simply returns the text to its own RNF.

Step 2 ensures that the file is normalized with respect to the eol-style (and, in theory, any keywords [5]) that will be in use after the merge. This prevents the merge from thinking that every line has changed, which is helpful in cases such as when the text already had the new-style line endings and the purpose of the merge is just to add the property.

Notes

Note [1]: The WC merge code currently has 'binary' overriding 'special' if both old and new props indicate 'binary': see detranslate_wc_file(). Looks like a bug, as 'special' takes precedence over all other translations in other cases.

Note [2]: A symlink doesn't have any on-disk attributes of its own on typical Unix-style filesystems so I imagine Subversion shouldn't be trying to change them. However, when checked out on a system that doesn't support symlinks, it becomes a normal file, and maybe then we apply the attributes.

Note [3]: (Bert says:) Merge uses a different kind of repository normal form than our pristine store... Merge always normalizes EOL to '\n' for any svn:eol-style, while our pristine handling only does that for 'native' and '\n' itself.

Note [4]: If the merged properties have conflicts, then ###?

Note [5]: In practice we don't currently detranslate (normalize) any keywords that are present in the 'mine' text but not enabled, and that become enabled by the new value of svn:keyword property. See detranslate_wc_file().

Text Merge

Executable and Read-Only Attributes

External Merge Tool

An external 3-way text merge tool may be configured. It is used instead of the internal text merge. It is only used when a text merge is deemed appropriate, and not when the file content is deemed 'binary', nor for a trivial merge.