Index: trunk/src/org/openstreetmap/josm/actions/JoinAreasAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/JoinAreasAction.java	(revision 15851)
+++ trunk/src/org/openstreetmap/josm/actions/JoinAreasAction.java	(revision 15852)
@@ -183,4 +183,9 @@
                     Objects.equals(way, that.way);
         }
+
+        @Override
+        public String toString() {
+            return "w" + way.getUniqueId() + " " + way.getNodesCount() + " nodes";
+        }
     }
 
@@ -254,5 +259,5 @@
          */
         WayTraverser(Collection<WayInPolygon> ways) {
-            availableWays = new HashSet<>(ways);
+            availableWays = new LinkedHashSet<>(ways);
             lastWay = null;
         }
@@ -482,4 +487,5 @@
      */
     public void join(Collection<Way> ways) {
+        cmdsCount = 0;
         addedRelations.clear();
 
@@ -548,4 +554,6 @@
                 commitCommands(tr("Move tags from ways to relations"));
 
+                makeCommitsOneAction(marktr("Joined overlapping areas"));
+
                 if (result.polygons != null && ds != null) {
                     List<Way> allWays = new ArrayList<>();
@@ -569,5 +577,10 @@
             if (addUndoRedo) {
                 UndoRedoHandler.getInstance().undo();
-                UndoRedoHandler.getInstance().getRedoCommands().clear();
+                // add no-change commands to the stack to remove the half-done commands
+                Way w = ways.iterator().next();
+                cmds.add(new ChangeCommand(w, w));
+                cmds.add(new ChangeCommand(w, w));
+                commitCommands(tr("Reverting changes"));
+                UndoRedoHandler.getInstance().undo();
             }
         }
@@ -597,6 +610,7 @@
      * @return new area formed.
      * @throws UserCancelException if user cancels the operation
-     */
-    public JoinAreasResult joinAreas(List<Multipolygon> areas) throws UserCancelException {
+     * @since xxx : visibility changed from public to private
+     */
+    private JoinAreasResult joinAreas(List<Multipolygon> areas) throws UserCancelException {
 
         // see #11026 - Because <ways> is a dynamic filtered (on ways) of a filtered (on selected objects) collection,
@@ -705,6 +719,4 @@
             }
         }
-
-        makeCommitsOneAction(marktr("Joined overlapping areas"));
 
         if (warnAboutRelations) {
@@ -1008,5 +1020,31 @@
         }
 
+        revertDuplicateTwoNodeWays(result);
+
         return result;
+    }
+
+    /**
+     * Correct possible error in markWayInsideSide result when splitting a self-intersecting way.
+     * If we have two ways with the same two nodes and the same direction there must be a self intersection.
+     * Change the direction flag for the latter of the two ways. The result is that difference between the number
+     * of ways with insideToTheRight = {@code true} and those with insideToTheRight = {@code false}
+     * differs by 0 or 1, not more.
+     * <p>See #10511
+     * @param parts the parts of a single closed way
+     */
+    private static void revertDuplicateTwoNodeWays(List<WayInPolygon> parts) {
+        for (int i = 0; i < parts.size(); i++) {
+            WayInPolygon w1 = parts.get(i);
+            if (w1.way.getNodesCount() != 2)
+                continue;
+            for (int j = i + 1; j < parts.size(); j++) {
+                WayInPolygon w2 = parts.get(j);
+                if (w2.way.getNodesCount() == 2 && w1.insideToTheRight == w2.insideToTheRight
+                        && w1.way.firstNode() == w2.way.firstNode() && w1.way.lastNode() == w2.way.lastNode()) {
+                    w2.insideToTheRight = !w2.insideToTheRight;
+                }
+            }
+        }
     }
 
@@ -1162,5 +1200,4 @@
                 cleanMultigonWays.add(way);
         }
-
         WayTraverser traverser = new WayTraverser(cleanMultigonWays);
         List<AssembledPolygon> result = new ArrayList<>();
