diff --git a/src/libs/utils/changeset.cpp b/src/libs/utils/changeset.cpp
index 2f8ad44a490617f239452f2735fe09053177333c..b006106a16ba29e34066a71b2f9408a8267315e4 100644
--- a/src/libs/utils/changeset.cpp
+++ b/src/libs/utils/changeset.cpp
@@ -70,12 +70,12 @@ bool ChangeSet::hasOverlap(int pos, int length)
 
         switch (cmd.type) {
         case EditOp::Replace:
-            if (overlaps(pos, length, cmd.pos1, cmd.length))
+            if (overlaps(pos, length, cmd.pos1, cmd.length1))
                 return true;
             break;
 
         case EditOp::Move:
-            if (overlaps(pos, length, cmd.pos1, cmd.length))
+            if (overlaps(pos, length, cmd.pos1, cmd.length1))
                 return true;
             if (cmd.pos2 > pos && cmd.pos2 < pos + length)
                 return true;
@@ -87,19 +87,19 @@ bool ChangeSet::hasOverlap(int pos, int length)
             break;
 
         case EditOp::Remove:
-            if (overlaps(pos, length, cmd.pos1, cmd.length))
+            if (overlaps(pos, length, cmd.pos1, cmd.length1))
                 return true;
             break;
 
         case EditOp::Flip:
-            if (overlaps(pos, length, cmd.pos1, cmd.length))
+            if (overlaps(pos, length, cmd.pos1, cmd.length1))
                 return true;
-            if (overlaps(pos, length, cmd.pos2, cmd.length))
+            if (overlaps(pos, length, cmd.pos2, cmd.length2))
                 return true;
             break;
 
         case EditOp::Copy:
-            if (overlaps(pos, length, cmd.pos1, cmd.length))
+            if (overlaps(pos, length, cmd.pos1, cmd.length1))
                 return true;
             if (cmd.pos2 > pos && cmd.pos2 < pos + length)
                 return true;
@@ -138,7 +138,7 @@ bool ChangeSet::replace(int pos, int length, const QString &replacement)
 
     EditOp cmd(EditOp::Replace);
     cmd.pos1 = pos;
-    cmd.length = length;
+    cmd.length1 = length;
     cmd.text = replacement;
     m_operationList += cmd;
 
@@ -154,7 +154,7 @@ bool ChangeSet::move(int pos, int length, int to)
 
     EditOp cmd(EditOp::Move);
     cmd.pos1 = pos;
-    cmd.length = length;
+    cmd.length1 = length;
     cmd.pos2 = to;
     m_operationList += cmd;
 
@@ -181,23 +181,24 @@ bool ChangeSet::remove(int pos, int length)
 
     EditOp cmd(EditOp::Remove);
     cmd.pos1 = pos;
-    cmd.length = length;
+    cmd.length1 = length;
     m_operationList += cmd;
 
     return !m_error;
 }
 
-bool ChangeSet::flip(int pos1, int length, int pos2)
+bool ChangeSet::flip(int pos1, int length1, int pos2, int length2)
 {
-    if (hasOverlap(pos1, length)
-        || hasOverlap(pos2, length)
-        || overlaps(pos1, length, pos2, length))
+    if (hasOverlap(pos1, length1)
+        || hasOverlap(pos2, length2)
+        || overlaps(pos1, length1, pos2, length2))
         m_error = true;
 
     EditOp cmd(EditOp::Flip);
     cmd.pos1 = pos1;
-    cmd.length = length;
+    cmd.length1 = length1;
     cmd.pos2 = pos2;
+    cmd.length2 = length2;
     m_operationList += cmd;
 
     return !m_error;
@@ -212,7 +213,7 @@ bool ChangeSet::copy(int pos, int length, int to)
 
     EditOp cmd(EditOp::Copy);
     cmd.pos1 = pos;
-    cmd.length = length;
+    cmd.length1 = length;
     cmd.pos2 = to;
     m_operationList += cmd;
 
@@ -223,21 +224,22 @@ void ChangeSet::doReplace(const EditOp &replace, QList<EditOp> *replaceList)
 {
     Q_ASSERT(replace.type == EditOp::Replace);
 
-    int diff = replace.text.size() - replace.length;
     {
         QMutableListIterator<EditOp> i(*replaceList);
         while (i.hasNext()) {
             EditOp &c = i.next();
             if (replace.pos1 <= c.pos1)
-                c.pos1 += diff;
+                c.pos1 += replace.text.size();
+            if (replace.pos1 < c.pos1)
+                c.pos1 -= replace.length1;
         }
     }
 
     if (m_string) {
-        m_string->replace(replace.pos1, replace.length, replace.text);
+        m_string->replace(replace.pos1, replace.length1, replace.text);
     } else if (m_cursor) {
         m_cursor->setPosition(replace.pos1);
-        m_cursor->setPosition(replace.pos1 + replace.length, QTextCursor::KeepAnchor);
+        m_cursor->setPosition(replace.pos1 + replace.length1, QTextCursor::KeepAnchor);
         m_cursor->insertText(replace.text);
     }
 }
@@ -254,11 +256,11 @@ void ChangeSet::convertToReplace(const EditOp &op, QList<EditOp> *replaceList)
 
     case EditOp::Move:
         replace1.pos1 = op.pos1;
-        replace1.length = op.length;
+        replace1.length1 = op.length1;
         replaceList->append(replace1);
 
         replace2.pos1 = op.pos2;
-        replace2.text = textAt(op.pos1, op.length);
+        replace2.text = textAt(op.pos1, op.length1);
         replaceList->append(replace2);
         break;
 
@@ -270,25 +272,25 @@ void ChangeSet::convertToReplace(const EditOp &op, QList<EditOp> *replaceList)
 
     case EditOp::Remove:
         replace1.pos1 = op.pos1;
-        replace1.length = op.length;
+        replace1.length1 = op.length1;
         replaceList->append(replace1);
         break;
 
     case EditOp::Flip:
         replace1.pos1 = op.pos1;
-        replace1.length = op.length;
-        replace1.text = textAt(op.pos2, op.length);
+        replace1.length1 = op.length1;
+        replace1.text = textAt(op.pos2, op.length2);
         replaceList->append(replace1);
 
         replace2.pos1 = op.pos2;
-        replace2.length = op.length;
-        replace2.text = textAt(op.pos1, op.length);
+        replace2.length1 = op.length2;
+        replace2.text = textAt(op.pos1, op.length1);
         replaceList->append(replace2);
         break;
 
     case EditOp::Copy:
         replace1.pos1 = op.pos2;
-        replace1.text = textAt(op.pos1, op.length);
+        replace1.text = textAt(op.pos1, op.length1);
         replaceList->append(replace1);
         break;
 
diff --git a/src/libs/utils/changeset.h b/src/libs/utils/changeset.h
index 7f953b402a9e5933e7b996dda51c3f47016d2801..2f46bd835d3e1f3aa3d74add24e5469f2a29a876 100644
--- a/src/libs/utils/changeset.h
+++ b/src/libs/utils/changeset.h
@@ -66,13 +66,14 @@ public:
             Copy
         };
 
-        EditOp(): type(Unset), pos1(0), pos2(0), length(0) {}
-        EditOp(Type t): type(t), pos1(0), pos2(0), length(0) {}
+        EditOp(): type(Unset), pos1(0), pos2(0), length1(0), length2(0) {}
+        EditOp(Type t): type(t), pos1(0), pos2(0), length1(0), length2(0) {}
 
         Type type;
         int pos1;
         int pos2;
-        int length;
+        int length1;
+        int length2;
         QString text;
     };
 
@@ -89,7 +90,7 @@ public:
     bool move(int pos, int length, int to);
     bool insert(int pos, const QString &text);
     bool remove(int pos, int length);
-    bool flip(int pos1, int length, int pos2);
+    bool flip(int pos1, int length1, int pos2, int length2);
     bool copy(int pos, int length, int to);
 
     bool hadErrors();
diff --git a/tests/auto/changeset/tst_changeset.cpp b/tests/auto/changeset/tst_changeset.cpp
index 89e7be59d8467dae33eb72806bd9a6faaac2e1b6..0071419b3a471ff1ce8ab9b8ab3ba71401ae3a1d 100644
--- a/tests/auto/changeset/tst_changeset.cpp
+++ b/tests/auto/changeset/tst_changeset.cpp
@@ -204,60 +204,74 @@ void tst_ChangeSet::singleFlip()
     {
         Utils::ChangeSet cs;
         QString test("abcdef");
-        QVERIFY(cs.flip(0, 2, 4));
+        QVERIFY(cs.flip(0, 2, 3, 3));
         cs.apply(&test);
-        QCOMPARE(test, QLatin1String("efcdab"));
+        QCOMPARE(test, QLatin1String("defcab"));
     }
     {
         Utils::ChangeSet cs;
         QString test("abcdef");
-        QVERIFY(cs.flip(1, 2, 3));
+        QVERIFY(cs.flip(1, 2, 3, 1));
         cs.apply(&test);
-        QCOMPARE(test, QLatin1String("adebcf"));
+        QCOMPARE(test, QLatin1String("adbcef"));
     }
     {
         Utils::ChangeSet cs;
         QString test("abcdef");
-        QVERIFY(cs.flip(3, 0, 4));
+        QVERIFY(cs.flip(3, 0, 4, 0));
         cs.apply(&test);
         QCOMPARE(test, QLatin1String("abcdef"));
     }
     {
         Utils::ChangeSet cs;
         QString test("abcdef");
-        QVERIFY(cs.flip(0, 6, 6));
+        QVERIFY(cs.flip(3, 0, 4, 1));
+        cs.apply(&test);
+        QCOMPARE(test, QLatin1String("abcedf"));
+    }
+    {
+        Utils::ChangeSet cs;
+        QString test("abcdef");
+        QVERIFY(cs.flip(0, 6, 6, 6));
         cs.apply(&test);
         QCOMPARE(test, QLatin1String("abcdef"));
     }
     {
         Utils::ChangeSet cs;
         QString test("abcdef");
-        QVERIFY(cs.flip(0, 6, 7));
+        QVERIFY(cs.flip(0, 6, 7, 3));
         cs.apply(&test);
         // ### maybe this should expand the string or error?
         QCOMPARE(test, QLatin1String(""));
     }
     {
         Utils::ChangeSet cs;
-        QCOMPARE(cs.flip(0, 3, 1), false);
+        QCOMPARE(cs.flip(0, 3, 1, 3), false);
     }
     {
         Utils::ChangeSet cs;
-        QCOMPARE(cs.flip(0, 3, 2), false);
+        QCOMPARE(cs.flip(0, 3, 2, 3), false);
     }
     {
         Utils::ChangeSet cs;
-        QVERIFY(cs.flip(3, 3, 0));
+        QVERIFY(cs.flip(0, 3, 0, 0));
         QString test("abcdef");
         cs.apply(&test);
-        QCOMPARE(test, QLatin1String("defabc"));
+        QCOMPARE(test, QLatin1String("abcdef"));
     }
     {
         Utils::ChangeSet cs;
-        QVERIFY(cs.flip(0, 3, 3));
+        QVERIFY(cs.flip(0, 0, 0, 3));
         QString test("abcdef");
         cs.apply(&test);
-        QCOMPARE(test, QLatin1String("defabc"));
+        QCOMPARE(test, QLatin1String("abcdef"));
+    }
+    {
+        Utils::ChangeSet cs;
+        QVERIFY(cs.flip(0, 3, 3, 0));
+        QString test("abcdef");
+        cs.apply(&test);
+        QCOMPARE(test, QLatin1String("abcdef"));
     }
 }