Index: trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java	(revision 6958)
+++ trunk/src/org/openstreetmap/josm/actions/UnGlueAction.java	(revision 6959)
@@ -22,4 +22,5 @@
 import org.openstreetmap.josm.command.AddCommand;
 import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.ChangeNodesCommand;
 import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.command.SequenceCommand;
@@ -71,4 +72,5 @@
         if (checkSelection(selection)) {
             if (!checkAndConfirmOutlyingUnglue()) {
+                // FIXME: Leaving action without clearing selectedNode, selectedWay, selectedNodes
                 return;
             }
@@ -81,12 +83,18 @@
             }
             if (count < 2) {
+                boolean selfCrossing = false;
+                if (count == 1) {
+                    // First try unglue self-crossing way
+                    selfCrossing = unglueSelfCrossingWay();
+                }
                 // If there aren't enough ways, maybe the user wanted to unglue the nodes
                 // (= copy tags to a new node)
-                if (checkForUnglueNode(selection)) {
-                    unglueNode(e);
-                } else {
-                    errorTime = Notification.TIME_SHORT;
-                    errMsg = tr("This node is not glued to anything else.");
-                }
+                if (!selfCrossing)
+                    if (checkForUnglueNode(selection)) {
+                        unglueNode(e);
+                    } else {
+                        errorTime = Notification.TIME_SHORT;
+                        errMsg = tr("This node is not glued to anything else.");
+                    }
             } else {
                 // and then do the work.
@@ -95,4 +103,5 @@
         } else if (checkSelection2(selection)) {
             if (!checkAndConfirmOutlyingUnglue()) {
+                // FIXME: Leaving action without clearing selectedNode, selectedWay, selectedNodes
                 return;
             }
@@ -379,10 +388,61 @@
 
         fixRelations(selectedNode, cmds, newNodes);
-
+        execCommands(cmds, newNodes);
+    }
+
+    /**
+     * Add commands to undo-redo system.
+     * @param cmds Commands to execute
+     * @param newNodes New created nodes by this set of command
+     */
+    private void execCommands(List<Command> cmds, List<Node> newNodes) {
         Main.main.undoRedo.add(new SequenceCommand(/* for correct i18n of plural forms - see #9110 */
                 trn("Dupe into {0} node", "Dupe into {0} nodes", newNodes.size() + 1, newNodes.size() + 1), cmds));
         // select one of the new nodes
-        getCurrentDataSet().setSelected(newNodes.getFirst());
-    }
+        getCurrentDataSet().setSelected(newNodes.get(0));
+    }
+
+    /**
+     * Duplicates a node used several times by the same way. See #9896.
+     * @return true if action is OK false if there is nothing to do
+     */
+    private boolean unglueSelfCrossingWay() {
+        // According to previous check, only one valid way through that node
+        LinkedList<Command> cmds = new LinkedList<Command>();
+        Way way = null;
+        for (Way w: OsmPrimitive.getFilteredList(selectedNode.getReferrers(), Way.class))
+            if (w.isUsable() && w.getNodesCount() >= 1) {
+                way = w;
+            }
+        List<Node> oldNodes = way.getNodes();
+        ArrayList<Node> newNodes = new ArrayList<Node>(oldNodes.size());
+        ArrayList<Node> addNodes = new ArrayList<Node>();
+        boolean seen = false;
+        for (Node n: oldNodes) {
+            if (n == selectedNode) {
+                if (seen) {
+                    Node newNode = new Node(n, true /* clear OSM ID */);
+                    newNodes.add(newNode);
+                    cmds.add(new AddCommand(newNode));
+                    newNodes.add(newNode);
+                    addNodes.add(newNode);
+                } else {
+                    newNodes.add(n);
+                    seen = true;
+                }
+            } else {
+                newNodes.add(n);
+            }
+        }
+        if (addNodes.isEmpty()) {
+            // selectedNode doesn't need unglue
+            return false;
+        }
+        cmds.add(new ChangeNodesCommand(way, newNodes));
+        // Update relation
+        fixRelations(selectedNode, cmds, addNodes);
+        execCommands(cmds, addNodes);
+        return true;
+     }
 
     /**
