Index: subversion/libsvn_fs_base/tree.c
===================================================================
--- subversion/libsvn_fs_base/tree.c	(revision 21872)
+++ subversion/libsvn_fs_base/tree.c	(working copy)
@@ -38,6 +38,7 @@
 #include "svn_error.h"
 #include "svn_path.h"
 #include "svn_md5.h"
+#include "svn_mergeinfo.h"
 #include "svn_fs.h"
 #include "svn_sorts.h"
 #include "fs.h"
@@ -1281,7 +1282,48 @@
   return SVN_NO_ERROR;
 }
 
+/* The input for txn_body_change_merge_info(). */
+struct change_merge_info_args
+{
+  svn_fs_root_t *root;
+  const char *path;
+  const svn_string_t *value;
+};
 
+/* Set the merge info on the transaction in BATON (expected to be of
+   type "struct change_merge_info_args").  Conforms to the callback
+   API used by svn_fs_base__retry_txn(). */
+static svn_error_t *
+txn_body_change_merge_info(void *baton,
+                           trail_t *trail)
+{
+  struct change_merge_info_args *args = baton;
+  SVN_ERR(svn_fs_base__set_txn_merge_info(args->root->fs, args->root->txn, 
+                                          args->path, args->value,
+                                          trail, trail->pool));
+  return SVN_NO_ERROR;
+}
+
+/* Change the merge info for the specified PATH to MERGE_INFO.  */
+static svn_error_t *
+base_change_merge_info(svn_fs_root_t *root,
+                       const char *path,
+                       apr_hash_t *merge_info,
+                       apr_pool_t *pool)
+{
+  svn_stringbuf_t *minfostr;
+  struct change_merge_info_args args;
+
+  if (! root->is_txn_root)
+    return NOT_TXN(root);
+  SVN_ERR(svn_mergeinfo_to_string(&minfostr, merge_info, pool));
+  args.root = root;
+  args.path = path;
+  args.value = svn_string_create_from_buf(minfostr, pool);
+  return svn_fs_base__retry_txn(root->fs, txn_body_change_merge_info, &args,
+                                pool);
+}
+
 struct change_node_prop_args {
   svn_fs_root_t *root;
   const char *path;
@@ -1291,6 +1333,24 @@
 
 
 static svn_error_t *
+change_txn_merge_info(struct change_node_prop_args *args, trail_t *trail)
+{
+  const char *txn_id = args->root->txn;
+
+  /* At least for single file merges, nodes which are direct
+     children of the root are received without a leading slash
+     (e.g. "/file.txt" is received as "file.txt"), so must be made
+     absolute. */
+  const char *canon_path = svn_fs_base__canonicalize_abspath(args->path, 
+                                                             trail->pool);
+  SVN_ERR(svn_fs_base__set_txn_merge_info(args->root->fs, txn_id, canon_path,
+                                          args->value, trail, trail->pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
 txn_body_change_node_prop(void *baton,
                           trail_t *trail)
 {
@@ -1321,6 +1381,9 @@
   if (! proplist)
     proplist = apr_hash_make(trail->pool);
 
+  if (strcmp(args->name, SVN_PROP_MERGE_INFO) == 0)
+    SVN_ERR(change_txn_merge_info(args, trail));
+
   /* Set the property. */
   apr_hash_set(proplist, args->name, APR_HASH_KEY_STRING, args->value);
 
@@ -2382,8 +2445,7 @@
   SVN_ERR(verify_locks(txn_name, trail, trail->pool));
 
   /* Else, commit the txn. */
-  SVN_ERR(svn_fs_base__dag_commit_txn(&(args->new_rev), fs, txn_name,
-                                      trail, trail->pool));
+  SVN_ERR(svn_fs_base__dag_commit_txn(&(args->new_rev), txn, trail));
 
   return SVN_NO_ERROR;
 }
@@ -4374,7 +4436,7 @@
   base_contents_changed,
   base_get_file_delta_stream,
   base_merge,
-  NULL,
+  base_change_merge_info,
   svn_fs_merge_info__get_merge_info
 };
 
Index: subversion/libsvn_fs_base/dag.h
===================================================================
--- subversion/libsvn_fs_base/dag.h	(revision 21872)
+++ subversion/libsvn_fs_base/dag.h	(working copy)
@@ -214,10 +214,8 @@
    Consume temporary space at most proportional to the maximum depth
    of SVN_TXN's tree of mutable nodes.  */
 svn_error_t *svn_fs_base__dag_commit_txn(svn_revnum_t *new_rev,
-                                         svn_fs_t *fs,
-                                         const char *txn_id,
-                                         trail_t *trail,
-                                         apr_pool_t *pool);
+                                         svn_fs_txn_t *txn,
+                                         trail_t *trail);
 
 
 
Index: subversion/libsvn_fs_base/tree.h
===================================================================
--- subversion/libsvn_fs_base/tree.h	(revision 21872)
+++ subversion/libsvn_fs_base/tree.h	(working copy)
@@ -15,6 +15,9 @@
  * ====================================================================
  */
 
+#include "svn_props.h"
+#include "trail.h"
+
 #ifndef SVN_LIBSVN_FS_TREE_H
 #define SVN_LIBSVN_FS_TREE_H
 
@@ -22,6 +25,10 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/* A transaction property which maps to a skel form of apr_hash_t
+   (target wc path char * -> actual merge info). */
+#define SVN_FS_PROP_TXN_MERGEINFO     SVN_PROP_PREFIX "txn-mergeinfo"
+
 
 
 /* These functions implement some of the calls in the FS loader
Index: subversion/libsvn_fs_base/revs-txns.c
===================================================================
--- subversion/libsvn_fs_base/revs-txns.c	(revision 21872)
+++ subversion/libsvn_fs_base/revs-txns.c	(working copy)
@@ -558,7 +558,47 @@
   return put_txn(fs, txn, txn_name, trail, pool);
 }
 
+svn_error_t *
+svn_fs_base__set_txn_merge_info(svn_fs_t *fs,
+                                const char *txn_name,
+                                const char *path,
+                                const svn_string_t *value,
+                                trail_t *trail,
+                                apr_pool_t *pool)
+{
+  transaction_t *txn;
+  apr_hash_t *target_mergeinfo;
 
+  SVN_ERR(get_txn(&txn, fs, txn_name, FALSE, trail, pool));
+  if (txn->kind != transaction_kind_normal)
+    return svn_fs_base__err_txn_not_mutable(fs, txn_name);
+
+  if (txn->proplist == NULL)
+    {
+     /* If we're deleting a property, exit now.  Otherwise, create a
+        proplist. */
+      if (value == NULL)
+        return SVN_NO_ERROR;
+
+      txn->proplist = apr_hash_make(pool);
+    }
+
+  target_mergeinfo = apr_hash_get(txn->proplist, SVN_FS_PROP_TXN_MERGEINFO,
+                                  APR_HASH_KEY_STRING);
+  if (target_mergeinfo == NULL)
+    target_mergeinfo = apr_hash_make(pool);
+
+  /* Set the mergeinfo for the path. */
+  apr_hash_set(target_mergeinfo, path, APR_HASH_KEY_STRING, value);
+
+  /* Set the property. */
+  apr_hash_set(txn->proplist, SVN_FS_PROP_TXN_MERGEINFO, 
+               APR_HASH_KEY_STRING, target_mergeinfo);
+
+  /* Now overwrite the transaction. */
+  return put_txn(fs, txn, txn_name, trail, pool);
+}
+
 static svn_error_t *
 txn_body_change_txn_prop(void *baton, trail_t *trail)
 {
@@ -587,7 +627,42 @@
   return SVN_NO_ERROR;
 }
 
+/* txn_vtable's get_mergeinfo hook.  Set TABLE_P to a merge info hash
+   (possibly empty), or NULL if there are no transaction
+   properties. */
+static svn_error_t *
+base_txn_merge_info(apr_hash_t **table_p,
+                    svn_fs_txn_t *txn,
+                    apr_pool_t *pool)
+{
+  apr_hash_t *txnprops = NULL;
+  apr_hash_t *target_mergeinfo;
+  struct txn_proplist_args args;
+  svn_fs_t *fs = txn->fs;
 
+  SVN_ERR(svn_fs_base__check_fs(fs));
+
+  args.table_p = &txnprops;
+  args.id = txn->id;
+  SVN_ERR(svn_fs_base__retry(fs, txn_body_txn_proplist, &args, pool));
+
+  if (txnprops)
+    {
+      target_mergeinfo = apr_hash_get(txnprops, SVN_FS_PROP_TXN_MERGEINFO,
+                                      APR_HASH_KEY_STRING);
+      if (!target_mergeinfo)
+        target_mergeinfo = apr_hash_make(pool);
+    }
+  else
+    {
+      target_mergeinfo = NULL;
+    }
+  *table_p = target_mergeinfo;
+
+  return SVN_NO_ERROR;
+}
+
+
 
 /* Creating a transaction */
 
@@ -598,7 +673,7 @@
   svn_fs_base__txn_proplist,
   svn_fs_base__change_txn_prop,
   svn_fs_base__txn_root,
-  NULL
+  base_txn_merge_info
 };
 
 
Index: subversion/libsvn_fs_base/revs-txns.h
===================================================================
--- subversion/libsvn_fs_base/revs-txns.h	(revision 21872)
+++ subversion/libsvn_fs_base/revs-txns.h	(working copy)
@@ -144,6 +144,20 @@
                                        apr_pool_t *pool);
 
 
+/* Set a PATH to VALUE for the SVN_FS_PROP_TXN_MERGEINFO property (a
+    hash table) on transaction TXN_NAME's proplist in FS as part of
+    TRAIL.  Use POOL for any necessary allocations.
+
+   Return SVN_ERR_FS_TRANSACTION_NOT_MUTABLE if TXN_NAME refers to a
+   transaction that has already been committed.  */
+svn_error_t *
+svn_fs_base__set_txn_merge_info(svn_fs_t *fs,
+                                const char *txn_name,
+                                const char *path,
+                                const svn_string_t *value,
+                                trail_t *trail,
+                                apr_pool_t *pool);
+
 /* Set a property NAME to VALUE on transaction TXN_NAME in FS as part
    of TRAIL.  Use POOL for any necessary allocations.
 
Index: subversion/libsvn_fs_base/dag.c
===================================================================
--- subversion/libsvn_fs_base/dag.c	(revision 21872)
+++ subversion/libsvn_fs_base/dag.c	(working copy)
@@ -34,6 +34,7 @@
 #include "reps-strings.h"
 #include "revs-txns.h"
 #include "id.h"
+#include "tree.h"  /* needed for SVN_FS_PROP_TXN_MERGEINFO */
 
 #include "util/fs_skels.h"
 
@@ -44,6 +45,7 @@
 #include "bdb/reps-table.h"
 #include "bdb/strings-table.h"
 
+#include "private/svn_fs_merge_info.h"
 #include "../libsvn_fs/fs-loader.h"
 
 #include "svn_private_config.h"
@@ -1416,18 +1418,35 @@
 
 svn_error_t *
 svn_fs_base__dag_commit_txn(svn_revnum_t *new_rev,
-                            svn_fs_t *fs,
-                            const char *txn_id,
-                            trail_t *trail,
-                            apr_pool_t *pool)
+                            svn_fs_txn_t *txn,
+                            trail_t *trail)
 {
   revision_t revision;
   svn_string_t date;
   apr_hash_t *txnprops;
+  svn_fs_t *fs = txn->fs;
+  const char *txn_id = txn->id;
+  apr_pool_t *pool = trail->pool;
+  apr_hash_t *target_mergeinfo;
 
   /* Remove any temporary transaction properties initially created by
      begin_txn().  */
   SVN_ERR(svn_fs_base__txn_proplist_in_trail(&txnprops, txn_id, trail));
+
+  /* Add new revision entry to `revisions' table. */
+  revision.txn_id = txn_id;
+  *new_rev = SVN_INVALID_REVNUM;
+  SVN_ERR(svn_fs_bdb__put_rev(new_rev, fs, &revision, trail, pool));
+
+  target_mergeinfo = apr_hash_get(txnprops, SVN_FS_PROP_TXN_MERGEINFO,
+                                  APR_HASH_KEY_STRING);
+  if (target_mergeinfo)
+    {
+      SVN_ERR(svn_fs_merge_info__update_index(txn, *new_rev, TRUE, pool));
+      SVN_ERR(svn_fs_base__set_txn_prop
+              (fs, txn_id, SVN_FS_PROP_TXN_MERGEINFO, NULL, trail, pool));
+    }
+
   if (txnprops)
     {
       if (apr_hash_get(txnprops, SVN_FS_PROP_TXN_CHECK_OOD,
@@ -1440,12 +1459,6 @@
         SVN_ERR(svn_fs_base__set_txn_prop 
                 (fs, txn_id, SVN_FS_PROP_TXN_CHECK_LOCKS, NULL, trail, pool));
     }
-
-  /* Add new revision entry to `revisions' table. */
-  revision.txn_id = txn_id;
-  *new_rev = SVN_INVALID_REVNUM;
-  SVN_ERR(svn_fs_bdb__put_rev(new_rev, fs, &revision, trail, pool));
-
   /* Promote the unfinished transaction to a committed one. */
   SVN_ERR(svn_fs_base__txn_make_committed(fs, txn_id, *new_rev, 
                                           trail, pool));
Index: subversion/libsvn_fs_base/util/fs_skels.c
===================================================================
--- subversion/libsvn_fs_base/util/fs_skels.c	(revision 21872)
+++ subversion/libsvn_fs_base/util/fs_skels.c	(working copy)
@@ -23,6 +23,7 @@
 #include "fs_skels.h"
 #include "skel.h"
 #include "../id.h"
+#include "../tree.h"  /* needed for SVN_FS_PROP_TXN_MERGEINFO */
 
 
 static svn_error_t *
@@ -56,15 +57,34 @@
 is_valid_proplist_skel(skel_t *skel)
 {
   int len = svn_fs_base__list_length(skel);
+  apr_size_t txn_mergeinfo_prop_length = strlen(SVN_FS_PROP_TXN_MERGEINFO);
 
   if ((len >= 0) && (len & 1) == 0)
     {
       skel_t *elt;
+      const char *propname = NULL;
+      apr_size_t propname_len = 0;
 
       for (elt = skel->children; elt; elt = elt->next)
-        if (! elt->is_atom)
-          return FALSE;
+        {
+          if (propname_len == txn_mergeinfo_prop_length && 
+              strncmp(propname, SVN_FS_PROP_TXN_MERGEINFO,
+                      txn_mergeinfo_prop_length) == 0)
+            {
+              if (elt->is_atom)
+                return FALSE;
+              len = svn_fs_base__list_length(elt);
+              if ((len & 1) != 0)
+                return FALSE;
+            }
+          else if (! elt->is_atom)
+            {
+              return FALSE;
+            }
 
+          propname = elt->data;
+          propname_len = elt->len;
+        }
       return TRUE;
     }
 
@@ -361,6 +381,38 @@
 
 /*** Parsing (conversion from skeleton to native FS type) ***/
 
+static svn_error_t *
+parse_txn_merge_info_skel(apr_hash_t **target_mergeinfo_p,
+                          skel_t *skel, apr_pool_t *pool)
+{
+  apr_hash_t *target_mergeinfo;
+
+  /* Create the returned structure */
+  if (skel->children)
+    {
+      skel_t *elt;
+      target_mergeinfo = apr_hash_make(pool);
+      for (elt = skel->children; elt; elt = elt->next->next)
+        {
+            svn_string_t *value = svn_string_ncreate(elt->next->data,
+                                                     elt->next->len, pool);
+            apr_hash_set(target_mergeinfo,
+                         apr_pstrmemdup(pool, elt->data, elt->len),
+                         elt->len, value);
+        }
+    }
+  else
+    {
+      target_mergeinfo = NULL;
+    }
+
+  /* Return the structure. */
+  *target_mergeinfo_p = target_mergeinfo;
+  return SVN_NO_ERROR;
+}
+
+/*** Parsing (conversion from skeleton to native FS type) ***/
+
 svn_error_t *
 svn_fs_base__parse_proplist_skel(apr_hash_t **proplist_p,
                                  skel_t *skel,
@@ -368,6 +420,7 @@
 {
   apr_hash_t *proplist = NULL;
   skel_t *elt;
+  apr_size_t txn_mergeinfo_prop_length = strlen(SVN_FS_PROP_TXN_MERGEINFO);
 
   /* Validate the skel. */
   if (! is_valid_proplist_skel(skel))
@@ -378,12 +431,23 @@
     proplist = apr_hash_make(pool);
   for (elt = skel->children; elt; elt = elt->next->next)
     {
-      svn_string_t *value = svn_string_ncreate(elt->next->data,
-                                               elt->next->len, pool);
-      apr_hash_set(proplist,
-                   apr_pstrmemdup(pool, elt->data, elt->len),
-                   elt->len,
-                   value);
+      if ((elt->len == txn_mergeinfo_prop_length) && 
+          strncmp(elt->data, SVN_FS_PROP_TXN_MERGEINFO, 
+                  txn_mergeinfo_prop_length) == 0)
+        {
+          apr_hash_t *target_mergeinfo;
+          SVN_ERR(parse_txn_merge_info_skel(&target_mergeinfo, elt->next,
+                                            pool));
+          apr_hash_set(proplist, apr_pstrmemdup(pool, elt->data, elt->len),
+                       elt->len, target_mergeinfo);
+        }
+      else
+        {
+          svn_string_t *value = svn_string_ncreate(elt->next->data,
+                                                   elt->next->len, pool);
+          apr_hash_set(proplist, apr_pstrmemdup(pool, elt->data, elt->len),
+                       elt->len, value);
+        }
     }
 
   /* Return the structure. */
@@ -863,6 +927,45 @@
 
 /*** Unparsing (conversion from native FS type to skeleton) ***/
 
+static svn_error_t *
+unparse_txn_merge_info_skel(skel_t **skel_p, apr_hash_t *target_mergeinfo,
+                            apr_pool_t *pool)
+{
+  skel_t *skel = svn_fs_base__make_empty_list(pool);
+  apr_hash_index_t *hi;
+
+  /* Create the skel. */
+  if (target_mergeinfo)
+    {
+      /* Loop over hash entries */
+      for (hi = apr_hash_first(pool, target_mergeinfo);
+           hi; hi = apr_hash_next(hi))
+        {
+          const void *key;
+          void *val;
+          apr_ssize_t klen;
+          svn_string_t *value;
+
+          apr_hash_this(hi, &key, &klen, &val);
+          value = val;
+
+          /* MERGEINFO */
+          svn_fs_base__prepend(svn_fs_base__mem_atom(value->data,
+                                                     value->len, pool),
+                               skel);
+
+          /* PATH */
+          svn_fs_base__prepend(svn_fs_base__mem_atom(key, klen, pool), skel);
+        }
+    }
+
+  /* Validate and return the skel. */
+  if (! is_valid_proplist_skel(skel))
+    return skel_err("proplist");
+  *skel_p = skel;
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_fs_base__unparse_proplist_skel(skel_t **skel_p,
                                    apr_hash_t *proplist,
@@ -870,6 +973,7 @@
 {
   skel_t *skel = svn_fs_base__make_empty_list(pool);
   apr_hash_index_t *hi;
+  apr_size_t txn_mergeinfo_prop_length = strlen(SVN_FS_PROP_TXN_MERGEINFO);
 
   /* Create the skel. */
   if (proplist)
@@ -886,9 +990,29 @@
           value = val;
 
           /* VALUE */
-          svn_fs_base__prepend(svn_fs_base__mem_atom(value->data,
-                                                     value->len, pool),
-                               skel);
+          if ((klen == txn_mergeinfo_prop_length) && 
+              strncmp(key, SVN_FS_PROP_TXN_MERGEINFO, 
+                      txn_mergeinfo_prop_length) == 0)
+            {
+              apr_hash_t *target_mergeinfo = val;
+              skel_t *target_mergeinfo_skel;
+              if (apr_hash_count(target_mergeinfo))
+                {
+                  unparse_txn_merge_info_skel(&target_mergeinfo_skel,
+                                              target_mergeinfo, pool);
+                  svn_fs_base__prepend(target_mergeinfo_skel, skel);
+                }
+              else
+                {
+                  continue;
+                }
+            }
+          else
+            {
+              svn_fs_base__prepend(svn_fs_base__mem_atom(value->data,
+                                                         value->len, pool),
+                                   skel);
+            }
 
           /* NAME */
           svn_fs_base__prepend(svn_fs_base__mem_atom(key, klen, pool), skel);

