You are here

Subversion mergeinfo

Mergeinfo

Mergeinfo the versioned property svn:mergeinfo, is the history of merges made into a given file or directory.

Explicit mergeinfo

When a path has the mergeinfo property set on it, that path is said to have explicit mergeinfo. The path can be a folder or a file.

Subtree mergeinfo

Normally mergeinfo is set only on the merge target. Subtree mergeinfo occurs:

  • when a merge target has some subtree that was previously a merge target itself (e.g. we merged from a file in trunk to a file in our branch, creating mergeinfo on that file).
  • when you rename/move something. This is regarded as defficiency of Subversion and may be fixed
  • when merging with incomplete represenation of repository (shallow working copy, switched subtrees, or because of authorization restrictions that prevent parts of a tree from being checked out)

Merge without modifying mergeinfo

There are a few cases where a merge won't create or modify mergeinfo:

  • when using the --ignore-ancestry option
  • the merge source is from a different repository from the merge target
  • reverse merging a change from a path's own history

Mergeinfo inheritance

If a path doesn't have explicit mergeinfo it can still have inherited mergeinfo if it has a parent (or grandparent, or great-grandparent, etc.) with explicit mergeinfo. The concept of "nearest parent" is not limited to the working copy. When determining the inherited mergeinfo on a path with no explicit mergeinfo, Subversion will first crawl as far up the working copy as it can looking for a parent with explicit mergeinfo. If it reaches the top of the working copy and can't find such a parent, it will then ask the repository about any other parent paths, going as far as the root of the repository if necessary. Only if no inheritable mergeinfo is found in the repository can we finally say the path has no mergeinfo whatsoever. When a path inherits mergeinfo, it does so only from its nearest parent with explicit mergeinfo.

Empty mergeinfo

Empty mergeinfo is a svn:mergeinfo property which has the empty string as a value. It simply means the state of this path is as if nothing was ever merged into it.

Mergeinfo elision

At the end of every merge Subversion tries to "consolidate" any redundant subtree mergeinfo. This consolidation process is called elision. Once a merge is completed, Subversion walks the working copy tree rooted at the merge target. If it finds a path with explicit mergeinfo which has a subtree with equivalent explicit mergeinfo, then the subtree's mergeinfo is elided (removed).

Reflective/cyclic merges

Suppose you are working on a feature branch copied from your trunk. During the development process you regularly merge all new changes from trunk to your branch so that the branch stays in "synch" with the work occurring on trunk. When you eventually merge your branch back to trunk, that is called a reflective (or cyclic) merge. Reflective merge has problems:

  • If we exclude the revisions that were merged from trunk, then we also exclude any work we did to resolve conflicts as part of those merges. Even worse, we might have carelessly committed unrelated changes as part of the merge (it happens) so those changes would also be excluded.
  • if we include those synched revisions, then we merge back changes that already exist in trunk. This yields unnecessary and confusing conflicts.

Subversion already has a technique that does the right thing with reflective merges. It is the one we used prior to 1.5 and is called a 2-URL merge (Reintegrate).

An important thing to point out is that once a branch is reintegrated, it should really be deleted. If more work needs to happen, create it again with a fresh copy. There are two reasons for this:

  • once you merge your branch to trunk, if you later want to synch all the changes with trunk back to the branch, you are now in this same reflective merge scenario with your branch!
  • if you do not merge trunk changes back to your branch because of the previous point, then when you go to reintegrate again it will try to merge everything again.

Reintegrate

The new reintegrate option is a shorthanded version of the 2-URL merge plus some safety checks. The checks make sure the working copy is at a single revision, with no switched children, and is not a sparse checkout (i.e. working copy depth is infinity). The most controversial reintegrate check is that the merge source does not have any subtree mergeinfo. Without these checks the 2-URL merge is prone to errors such as using from URL or wrong revision number. More on reintagrate can be found in Subversion merge reintegrate, section "Reintegrate to the Rescue".

Useful commands

Get mergeinfo on all tree, the XML format is needed to create readable output:
svn propget svn:mergeinfo --recursive --xml

Delete mergeinfo on tree except root (the merge target)
svn propdel --recursive svn:mergeinfo ./*

Resources

Subversion merge reintegrate
Subversion 1.5 Mergeinfo - Understanding the Internals

Comments

I noticed that svn propdel --recursive doesn't work if the properties are not set on files at the top level. If you want to delete all svn:mergeinfo from any subtree or file inside the branch, it's best to create a list of files on which to delete the property individually:

svn propget -R svn:mergeinfo --xml ./*
gives you output containing among others this list of files. If you're on unix, you can use grep and sed to massage the output so that all lines looking like
    path="path/to/some/file">
will be converted to
svn propdel svn:mergeinfo "path/to/some/file"
following line passes this output directly through bash so that it gets executed immediately:
svn propget -R svn:mergeinfo --xml ./*|grep ' path="'|sed -e 's/ path="/svn propdel svn:mergeinfo "/'|sed -e 's/>$//'|bash

Users of other platforms will have to use some advanced text editor, or install ports of grep and sed for their platform.

Before committing, it's best to verify you didn't miss any properties due to possible weirdness in the xml output, so run
svn propget -R svn:mergeinfo --xml ./*
again to double-check.

If I'm not mistaken this does the same as the above:

svn propdel -R svn:mergeinfo .
svn revert .

Updated, thanks for reminding me