diff --git a/NEWS b/NEWS
index 7ce44e0b627f7a543fe1ff7daf5bce54d032f43d..e396b1a2081abb8f209aa4b38fdae91ec42e4426 100644
--- a/NEWS
+++ b/NEWS
@@ -14,19 +14,7 @@ Version 2.6.0 beta1
 Version 2.5.0 rc5
 -----------------
 
-*(unreleased)*
-
-Improvements and bugfixes
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-- Support for kvm version 1.0, that changed the version reporting format
-  (from 3 to 2 digits).
-
-
-Version 2.5.0 rc4
------------------
-
-*(Released Thu, 27 Oct 2011)*
+*(Released Mon, 9 Jan 2012)*
 
 Incompatible/important changes and bugfixes
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -60,6 +48,9 @@ Incompatible/important changes and bugfixes
 - :doc:`New iallocator modes <design-multi-reloc>` have been added to
   support operations involving multiple node groups.
 - Offline nodes are ignored when failing over an instance.
+- Support for KVM version 1.0, which changed the version reporting format
+  from 3 to 2 digits.
+- Includes all bugfixes made in the 2.4 series
 
 New features
 ~~~~~~~~~~~~
@@ -153,6 +144,14 @@ Misc
 - DRBD metadata volumes are overwritten with zeros during disk creation.
 
 
+Version 2.5.0 rc4
+-----------------
+
+*(Released Thu, 27 Oct 2011)*
+
+This was the fourth release candidate of the 2.5 series.
+
+
 Version 2.5.0 rc3
 -----------------
 
diff --git a/configure.ac b/configure.ac
index 63a33d393ef01ea543dad4bdf673229e593b92f7..3dd5b691e661bb0424cfc87af4324982834ab3b9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 m4_define([gnt_version_major], [2])
 m4_define([gnt_version_minor], [5])
 m4_define([gnt_version_revision], [0])
-m4_define([gnt_version_suffix], [~rc4])
+m4_define([gnt_version_suffix], [~rc5])
 m4_define([gnt_version_full],
           m4_format([%d.%d.%d%s],
                     gnt_version_major, gnt_version_minor,
diff --git a/lib/cli.py b/lib/cli.py
index 282abad5f37029760f16a3c97046e04d92ca045c..a920fb0778d236df2776fda6a174049e86900a93 100644
--- a/lib/cli.py
+++ b/lib/cli.py
@@ -30,6 +30,7 @@ import logging
 import errno
 import itertools
 import shlex
+import optparse
 from cStringIO import StringIO
 
 from ganeti import utils
@@ -44,7 +45,7 @@ from ganeti import compat
 from ganeti import netutils
 from ganeti import qlang
 
-from optparse import (OptionParser, TitledHelpFormatter,
+from optparse import (TitledHelpFormatter,
                       Option, OptionValueError)
 
 
@@ -1480,10 +1481,10 @@ def _ParseArgs(argv, commands, aliases, env_override):
       argv = utils.InsertAtPos(argv, 1, shlex.split(env_args))
 
   func, args_def, parser_opts, usage, description = commands[cmd]
-  parser = OptionParser(option_list=parser_opts + COMMON_OPTS,
-                        description=description,
-                        formatter=TitledHelpFormatter(),
-                        usage="%%prog %s %s" % (cmd, usage))
+  parser = CustomOptionParser(option_list=parser_opts + COMMON_OPTS,
+                              description=description,
+                              formatter=TitledHelpFormatter(),
+                              usage="%%prog %s %s" % (cmd, usage))
   parser.disable_interspersed_args()
   options, args = parser.parse_args(args=argv[1:])
 
@@ -1493,6 +1494,21 @@ def _ParseArgs(argv, commands, aliases, env_override):
   return func, options, args
 
 
+class CustomOptionParser(optparse.OptionParser):
+  def _match_long_opt(self, opt):
+    """Override C{OptionParser}'s function for matching long options.
+
+    The default implementation does prefix-based abbreviation matching. We
+    disable such behaviour as it can can lead to confusing conflicts (e.g.
+    C{--force} and C{--force-multi}).
+
+    """
+    if opt in self._long_opt:
+      return opt
+    else:
+      raise optparse.BadOptionError(opt)
+
+
 def _CheckArguments(cmd, args_def, args):
   """Verifies the arguments using the argument definition.
 
diff --git a/lib/utils/text.py b/lib/utils/text.py
index 058ee859238163c8503626ad7ba7c35ce6b4be4e..02382642bff0282a6d831dc09d2e2e4fbadbaefb 100644
--- a/lib/utils/text.py
+++ b/lib/utils/text.py
@@ -387,10 +387,12 @@ def UnescapeAndSplit(text, sep=","):
       num_b = len(e1) - len(e1.rstrip("\\"))
       if num_b % 2 == 1 and slist:
         e2 = slist.pop(0)
-        # here the backslashes remain (all), and will be reduced in
-        # the next step
-        rlist.append(e1 + sep + e2)
+        # Merge the two elements and push the result back to the source list for
+        # revisiting. If e2 ended with backslashes, further merging may need to
+        # be done.
+        slist.insert(0, e1 + sep + e2)
         continue
+    # here the backslashes remain (all), and will be reduced in the next step
     rlist.append(e1)
   # finally, replace backslash-something with something
   rlist = [re.sub(r"\\(.)", r"\1", v) for v in rlist]
diff --git a/qa/qa_cluster.py b/qa/qa_cluster.py
index e662192650eb256d049eb8cb3ecb3866f89ae369..233cacb0c619bbfe7648b147fe341942e17b3b23 100644
--- a/qa/qa_cluster.py
+++ b/qa/qa_cluster.py
@@ -205,7 +205,7 @@ def TestClusterEpo():
 
   # Assert that OOB is unavailable for all nodes
   result_output = GetCommandOutput(master["primary"],
-                                   "gnt-node list --verbose --no-header -o"
+                                   "gnt-node list --verbose --no-headers -o"
                                    " powered")
   AssertEqual(compat.all(powered == "(unavail)"
                          for powered in result_output.splitlines()), True)
@@ -223,7 +223,7 @@ def TestClusterEpo():
 
   # All instances should have been stopped now
   result_output = GetCommandOutput(master["primary"],
-                                   "gnt-instance list --no-header -o status")
+                                   "gnt-instance list --no-headers -o status")
   AssertEqual(compat.all(status == "ADMIN_down"
                          for status in result_output.splitlines()), True)
 
@@ -232,7 +232,7 @@ def TestClusterEpo():
 
   # All instances should have been started now
   result_output = GetCommandOutput(master["primary"],
-                                   "gnt-instance list --no-header -o status")
+                                   "gnt-instance list --no-headers -o status")
   AssertEqual(compat.all(status == "running"
                          for status in result_output.splitlines()), True)
 
diff --git a/qa/qa_instance.py b/qa/qa_instance.py
index e235b09d250513ef662cdc7b56184693ceedc07a..a9b50a1337f1ad5c91d2ae9433abcd9c584196fa 100644
--- a/qa/qa_instance.py
+++ b/qa/qa_instance.py
@@ -112,7 +112,7 @@ def TestInstanceReboot(instance):
   AssertCommand(["gnt-instance", "reboot", name])
 
   master = qa_config.GetMasterNode()
-  cmd = ["gnt-instance", "list", "--no-header", "-o", "status", name]
+  cmd = ["gnt-instance", "list", "--no-headers", "-o", "status", name]
   result_output = qa_utils.GetCommandOutput(master["primary"],
                                             utils.ShellQuoteArgs(cmd))
   AssertEqual(result_output.strip(), constants.INSTST_RUNNING)
diff --git a/qa/qa_utils.py b/qa/qa_utils.py
index 671a6f21abf2ecb976a572c61a1371f590060564..4fdb46eb73f60e5690baea08f8513bff77fea9e7 100644
--- a/qa/qa_utils.py
+++ b/qa/qa_utils.py
@@ -400,7 +400,7 @@ def _List(listcmd, fields, names):
   """
   master = qa_config.GetMasterNode()
 
-  cmd = [listcmd, "list", "--separator=|", "--no-header",
+  cmd = [listcmd, "list", "--separator=|", "--no-headers",
          "--output", ",".join(fields)]
 
   if names:
diff --git a/test/ganeti.utils.text_unittest.py b/test/ganeti.utils.text_unittest.py
index 92a983600dd15eab489858770b94b7174604c5c1..1e91468e3195670979e02b65907e0ff6b8c998dd 100755
--- a/test/ganeti.utils.text_unittest.py
+++ b/test/ganeti.utils.text_unittest.py
@@ -408,6 +408,12 @@ class TestUnescapeAndSplit(unittest.TestCase):
       b = [sep, sep, "c", "d.moo\\"]
       self.assertEqual(utils.UnescapeAndSplit("%s\\" % sep.join(a), sep=sep), b)
 
+  def testMultipleEscapes(self):
+    for sep in self._seps:
+      a = ["a", "b\\" + sep + "c", "d\\" + sep + "e\\" + sep + "f", "g"]
+      b = ["a", "b" + sep + "c", "d" + sep + "e" + sep + "f", "g"]
+      self.failUnlessEqual(utils.UnescapeAndSplit(sep.join(a), sep=sep), b)
+
 
 class TestCommaJoin(unittest.TestCase):
   def test(self):
diff --git a/tools/cluster-merge b/tools/cluster-merge
index 7162d66c3759ca04302b9d7693b55b990acf3fe9..c3a0e09bcf443ef13c28679360045074eaac6f1c 100755
--- a/tools/cluster-merge
+++ b/tools/cluster-merge
@@ -192,7 +192,7 @@ class Merger(object):
       utils.WriteFile(key_path, mode=0600, data=result.stdout)
 
       result = self._RunCmd(cluster, "gnt-node list -o name,offline"
-                            " --no-header --separator=,", private_key=key_path)
+                            " --no-headers --separator=,", private_key=key_path)
       if result.failed:
         raise errors.RemoteError("Unable to retrieve list of nodes from %s."
                                  " Fail reason: %s; output: %s" %
@@ -201,7 +201,7 @@ class Merger(object):
       nodes = [node_status[0] for node_status in nodes_statuses
                if node_status[1] == "N"]
 
-      result = self._RunCmd(cluster, "gnt-instance list -o name --no-header",
+      result = self._RunCmd(cluster, "gnt-instance list -o name --no-headers",
                             private_key=key_path)
       if result.failed:
         raise errors.RemoteError("Unable to retrieve list of instances from"